diff options
859 files changed, 20296 insertions, 9230 deletions
diff --git a/StubLibraries.bp b/StubLibraries.bp index e6f50b7c4210..720bfc0897da 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -358,7 +358,7 @@ java_defaults { visibility: ["//visibility:private"], } -java_library_static { +java_library { name: "android-non-updatable.stubs", defaults: ["android-non-updatable_defaults_stubs_current"], srcs: [":api-stubs-docs-non-updatable"], @@ -368,7 +368,7 @@ java_library_static { }, } -java_library_static { +java_library { name: "android-non-updatable.stubs.system", defaults: ["android-non-updatable_defaults_stubs_current"], srcs: [":system-api-stubs-docs-non-updatable"], @@ -378,7 +378,7 @@ java_library_static { }, } -java_library_static { +java_library { name: "android-non-updatable.stubs.module_lib", defaults: ["android-non-updatable_defaults_stubs_current"], srcs: [":module-lib-api-stubs-docs-non-updatable"], @@ -392,7 +392,7 @@ java_library_static { }, } -java_library_static { +java_library { name: "android-non-updatable.stubs.test", defaults: ["android-non-updatable_defaults_stubs_current"], srcs: [":test-api-stubs-docs-non-updatable"], @@ -415,7 +415,7 @@ java_defaults { defaults_visibility: ["//frameworks/base/services"], } -java_library_static { +java_library { name: "android_stubs_current", static_libs: modules_public_stubs + [ "android-non-updatable.stubs", @@ -424,7 +424,7 @@ java_library_static { defaults: ["android.jar_defaults"], } -java_library_static { +java_library { name: "android_system_stubs_current", static_libs: modules_system_stubs + [ "android-non-updatable.stubs.system", @@ -450,7 +450,7 @@ java_library_static { ], } -java_library_static { +java_library { name: "android_test_stubs_current", // Modules do not have test APIs, but we want to include their SystemApis, like we include // the SystemApi of framework-non-updatable-sources. @@ -467,7 +467,7 @@ java_library_static { }, } -java_library_static { +java_library { name: "android_module_lib_stubs_current", defaults: [ "android.jar_defaults", @@ -482,6 +482,22 @@ java_library_static { }, } +java_library { + name: "android_system_server_stubs_current", + defaults: ["android_stubs_dists_default"], + srcs: [":services-non-updatable-stubs"], + installable: false, + static_libs: [ + "android_module_lib_stubs_current", + ], + sdk_version: "none", + system_modules: "none", + java_version: "1.8", + dist: { + dir: "apistubs/android/system-server", + }, +} + ///////////////////////////////////////////////////////////////////// // hwbinder.stubs provides APIs required for building HIDL Java // libraries. @@ -515,7 +531,7 @@ droidstubs { visibility: ["//visibility:private"], } -java_library_static { +java_library { name: "hwbinder.stubs", sdk_version: "core_current", libs: ["framework-annotations-lib"], diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java index 4357905f0371..0089c6dc8d2e 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java @@ -30,8 +30,6 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.ArraySet; -import com.android.internal.infra.AndroidFuture; - import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -43,6 +41,7 @@ import java.io.IOException; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; /** @@ -95,7 +94,7 @@ public class AppSearchMigrationHelper implements Closeable { File queryFile = File.createTempFile(/*prefix=*/"appsearch", /*suffix=*/null); try (ParcelFileDescriptor fileDescriptor = ParcelFileDescriptor.open(queryFile, MODE_WRITE_ONLY)) { - AndroidFuture<AppSearchResult<Void>> androidFuture = new AndroidFuture<>(); + CompletableFuture<AppSearchResult<Void>> future = new CompletableFuture<>(); mService.writeQueryResultsToFile(mPackageName, mDatabaseName, fileDescriptor, /*queryExpression=*/ "", @@ -106,11 +105,11 @@ public class AppSearchMigrationHelper implements Closeable { mUserId, new IAppSearchResultCallback.Stub() { @Override - public void onResult(AppSearchResult result) throws RemoteException { - androidFuture.complete(result); + public void onResult(AppSearchResult result) { + future.complete(result); } }); - AppSearchResult<Void> result = androidFuture.get(); + AppSearchResult<Void> result = future.get(); if (!result.isSuccess()) { throw new AppSearchException(result.getResultCode(), result.getErrorMessage()); } @@ -142,15 +141,15 @@ public class AppSearchMigrationHelper implements Closeable { } try (ParcelFileDescriptor fileDescriptor = ParcelFileDescriptor.open(mMigratedFile, MODE_READ_ONLY)) { - AndroidFuture<AppSearchResult<List<Bundle>>> androidFuture = new AndroidFuture<>(); + CompletableFuture<AppSearchResult<List<Bundle>>> future = new CompletableFuture<>(); mService.putDocumentsFromFile(mPackageName, mDatabaseName, fileDescriptor, mUserId, new IAppSearchResultCallback.Stub() { @Override - public void onResult(AppSearchResult result) throws RemoteException { - androidFuture.complete(result); + public void onResult(AppSearchResult result) { + future.complete(result); } }); - AppSearchResult<List<Bundle>> result = androidFuture.get(); + AppSearchResult<List<Bundle>> result = future.get(); if (!result.isSuccess()) { return AppSearchResult.newFailedResult(result); } diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java index 1e0d205230ca..64ac63c2b849 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java @@ -28,7 +28,6 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; -import com.android.internal.infra.AndroidFuture; import com.android.internal.util.Preconditions; import java.io.Closeable; @@ -37,6 +36,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -708,8 +708,8 @@ public final class AppSearchSession implements Closeable { try { // Migration process // 1. Validate and retrieve all active migrators. - AndroidFuture<AppSearchResult<GetSchemaResponse>> getSchemaFuture = - new AndroidFuture<>(); + CompletableFuture<AppSearchResult<GetSchemaResponse>> getSchemaFuture = + new CompletableFuture<>(); getSchema(callbackExecutor, getSchemaFuture::complete); AppSearchResult<GetSchemaResponse> getSchemaResult = getSchemaFuture.get(); if (!getSchemaResult.isSuccess()) { @@ -733,7 +733,8 @@ public final class AppSearchSession implements Closeable { // 2. SetSchema with forceOverride=false, to retrieve the list of // incompatible/deleted types. - AndroidFuture<AppSearchResult<Bundle>> setSchemaFuture = new AndroidFuture<>(); + CompletableFuture<AppSearchResult<Bundle>> setSchemaFuture = + new CompletableFuture<>(); mService.setSchema( mPackageName, mDatabaseName, @@ -781,8 +782,8 @@ public final class AppSearchSession implements Closeable { // failed. if (!setSchemaResponse.getIncompatibleTypes().isEmpty() || !setSchemaResponse.getDeletedTypes().isEmpty()) { - AndroidFuture<AppSearchResult<Bundle>> setSchema2Future = - new AndroidFuture<>(); + CompletableFuture<AppSearchResult<Bundle>> setSchema2Future = + new CompletableFuture<>(); // only trigger second setSchema() call if the first one is fail. mService.setSchema( mPackageName, diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl index 17f724b3a6f5..507bd6884cde 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl +++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl @@ -17,14 +17,9 @@ package android.app.appsearch; import android.os.Bundle; -import android.app.appsearch.AppSearchBatchResult; -import android.app.appsearch.AppSearchResult; import android.app.appsearch.IAppSearchBatchResultCallback; import android.app.appsearch.IAppSearchResultCallback; import android.os.ParcelFileDescriptor; -import com.android.internal.infra.AndroidFuture; - -parcelable SearchResults; /** {@hide} */ interface IAppSearchManager { diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java index 8a162d49e151..b7bd3878d4fa 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java @@ -96,8 +96,13 @@ public class SetSchemaResponse { } /** - * Returns a {@link Set} of schema type that were deleted by the {@link - * AppSearchSession#setSchema} call. + * Returns a {@link Set} of deleted schema types. + * + * <p>A "deleted" type is a schema type that was previously a part of the database schema but + * was not present in the {@link SetSchemaRequest} object provided in the + * {@link AppSearchSession#setSchema) call. + * + * <p>Documents for a deleted type are removed from the database. */ @NonNull public Set<String> getDeletedTypes() { @@ -113,6 +118,15 @@ public class SetSchemaResponse { /** * Returns a {@link Set} of schema type that were migrated by the {@link * AppSearchSession#setSchema} call. + * + * <p>A "migrated" type is a schema type that has triggered a {@link Migrator} instance to + * migrate documents of the schema type to another schema type, or to another version of the + * schema type. + * + * <p>If a document fails to be migrated, a {@link MigrationFailure} will be generated for that + * document. + * + * @see Migrator */ @NonNull public Set<String> getMigratedTypes() { @@ -132,6 +146,7 @@ public class SetSchemaResponse { * <p>If a {@link Migrator} is provided for this type and the migration is success triggered. * The type will also appear in {@link #getMigratedTypes()}. * + * @see SetSchemaRequest * @see AppSearchSession#setSchema * @see SetSchemaRequest.Builder#setForceOverride */ diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java b/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java index ca4ea2bfd3bb..62593ae8fc29 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java @@ -42,6 +42,8 @@ public class AppSearchException extends Exception { * Initializes an {@link AppSearchException} with a result code and message. * * @param resultCode One of the constants documented in {@link AppSearchResult#getResultCode}. + * @param message The detail message (which is saved for later retrieval by the {@link + * #getMessage()} method). */ public AppSearchException( @AppSearchResult.ResultCode int resultCode, @Nullable String message) { @@ -52,6 +54,11 @@ public class AppSearchException extends Exception { * Initializes an {@link AppSearchException} with a result code, message and cause. * * @param resultCode One of the constants documented in {@link AppSearchResult#getResultCode}. + * @param message The detail message (which is saved for later retrieval by the {@link + * #getMessage()} method). + * @param cause The cause (which is saved for later retrieval by the {@link #getCause()} + * method). (A null value is permitted, and indicates that the cause is nonexistent or + * unknown.) */ public AppSearchException( @AppSearchResult.ResultCode int resultCode, diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java index 7ca77d41cc89..a4188a2733b8 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -16,6 +16,7 @@ package com.android.server.appsearch; import static android.app.appsearch.AppSearchResult.throwableToFailedResult; +import static android.os.Process.INVALID_UID; import static android.os.UserHandle.USER_NULL; import android.annotation.ElapsedRealtimeLong; @@ -53,7 +54,6 @@ import android.os.UserManager; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; -import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; @@ -128,6 +128,17 @@ public class AppSearchManagerService extends SystemService { mContext.registerReceiverAsUser(new UserActionReceiver(), UserHandle.ALL, new IntentFilter(Intent.ACTION_USER_REMOVED), /*broadcastPermission=*/ null, /*scheduler=*/ null); + + //TODO(b/145759910) Add a direct callback when user clears the data instead of relying on + // broadcasts + IntentFilter packageChangedFilter = new IntentFilter(); + packageChangedFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); + packageChangedFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); + packageChangedFilter.addDataScheme("package"); + packageChangedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); + mContext.registerReceiverAsUser(new PackageChangedReceiver(), UserHandle.ALL, + packageChangedFilter, /*broadcastPermission=*/ null, + /*scheduler=*/ null); } private class UserActionReceiver extends BroadcastReceiver { @@ -135,15 +146,15 @@ public class AppSearchManagerService extends SystemService { public void onReceive(@NonNull Context context, @NonNull Intent intent) { switch (intent.getAction()) { case Intent.ACTION_USER_REMOVED: - final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); + int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); if (userId == USER_NULL) { - Slog.e(TAG, "userId is missing in the intent: " + intent); + Log.e(TAG, "userId is missing in the intent: " + intent); return; } handleUserRemoved(userId); break; default: - Slog.e(TAG, "Received unknown intent: " + intent); + Log.e(TAG, "Received unknown intent: " + intent); } } } @@ -163,9 +174,52 @@ public class AppSearchManagerService extends SystemService { try { mImplInstanceManager.removeAppSearchImplForUser(userId); mLoggerInstanceManager.removePlatformLoggerForUser(userId); - Slog.i(TAG, "Removed AppSearchImpl instance for user: " + userId); + Log.i(TAG, "Removed AppSearchImpl instance for user: " + userId); } catch (Throwable t) { - Slog.e(TAG, "Unable to remove data for user: " + userId, t); + Log.e(TAG, "Unable to remove data for user: " + userId, t); + } + } + + private class PackageChangedReceiver extends BroadcastReceiver { + @Override + public void onReceive(@NonNull Context context, @NonNull Intent intent) { + switch (intent.getAction()) { + case Intent.ACTION_PACKAGE_FULLY_REMOVED: + case Intent.ACTION_PACKAGE_DATA_CLEARED: + String packageName = intent.getData().getSchemeSpecificPart(); + if (packageName == null) { + Log.e(TAG, "Package name is missing in the intent: " + intent); + return; + } + int uid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID); + if (uid == INVALID_UID) { + Log.e(TAG, "uid is missing in the intent: " + intent); + return; + } + handlePackageRemoved(packageName, uid); + break; + default: + Log.e(TAG, "Received unknown intent: " + intent); + } + } + } + + private void handlePackageRemoved(String packageName, int uid) { + int userId = UserHandle.getUserId(uid); + try { + if (isUserLocked(userId)) { + //TODO(b/186151459) clear the uninstalled package data when user is unlocked. + return; + } + if (ImplInstanceManager.getAppSearchDir(userId).exists()) { + // Only clear the package's data if AppSearch exists for this user. + AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext, + userId); + //TODO(b/145759910) clear visibility setting for package. + impl.clearPackageData(packageName); + } + } catch (Throwable t) { + Log.e(TAG, "Unable to remove data for package: " + packageName, t); } } @@ -177,17 +231,20 @@ public class AppSearchManagerService extends SystemService { } private void verifyUserUnlocked(int callingUserId) { + if (isUserLocked(callingUserId)) { + throw new IllegalStateException("User " + callingUserId + " is locked or not running."); + } + } + + private boolean isUserLocked(int callingUserId) { synchronized (mUnlockedUserIdsLocked) { // First, check the local copy. if (mUnlockedUserIdsLocked.contains(callingUserId)) { - return; + return false; } // If the local copy says the user is locked, check with UM for the actual state, // since the user might just have been unlocked. - if (!mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(callingUserId))) { - throw new IllegalStateException( - "User " + callingUserId + " is locked or not running."); - } + return !mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(callingUserId)); } } @@ -444,7 +501,8 @@ public class AppSearchManagerService extends SystemService { packageName, databaseName, queryExpression, - new SearchSpec(searchSpecBundle)); + new SearchSpec(searchSpecBundle), + /*logger=*/ null); invokeCallbackOnResult( callback, AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); @@ -478,7 +536,8 @@ public class AppSearchManagerService extends SystemService { queryExpression, new SearchSpec(searchSpecBundle), packageName, - callingUid); + callingUid, + /*logger=*/ null); invokeCallbackOnResult( callback, AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); @@ -552,7 +611,8 @@ public class AppSearchManagerService extends SystemService { packageName, databaseName, queryExpression, - new SearchSpec(searchSpecBundle)); + new SearchSpec(searchSpecBundle), + /*logger=*/ null); while (!searchResultPage.getResults().isEmpty()) { for (int i = 0; i < searchResultPage.getResults().size(); i++) { AppSearchMigrationHelper.writeBundleToOutputStream( diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java index af39b790168c..94ee830f8e74 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java @@ -73,6 +73,15 @@ public final class ImplInstanceManager { } /** + * Returns AppSearch directory in the credential encrypted system directory for the given user. + * + * <p>This folder should only be accessed after unlock. + */ + public static File getAppSearchDir(@UserIdInt int userId) { + return new File(Environment.getDataSystemCeDirectory(userId), APP_SEARCH_DIR); + } + + /** * Gets an instance of AppSearchImpl for the given user, or creates one if none exists. * * <p>If no AppSearchImpl instance exists for the unlocked user, Icing will be initialized and @@ -139,13 +148,9 @@ public final class ImplInstanceManager { private AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId) throws AppSearchException { - File appSearchDir = getAppSearchDir(context, userId); - return AppSearchImpl.create(appSearchDir, context, userId, mGlobalQuerierPackage); - } - - private static File getAppSearchDir(@NonNull Context context, @UserIdInt int userId) { - // See com.android.internal.app.ChooserActivity::getPinnedSharedPrefs - return new File(Environment.getDataSystemCeDirectory(userId), APP_SEARCH_DIR); + File appSearchDir = getAppSearchDir(userId); + return AppSearchImpl.create( + appSearchDir, context, userId, mGlobalQuerierPackage, /*logger=*/ null); } /** diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java index 98fcb1370d8b..e5e20e733264 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java @@ -54,7 +54,9 @@ import com.android.server.appsearch.external.localstorage.converter.SearchResult import com.android.server.appsearch.external.localstorage.converter.SearchSpecToProtoConverter; import com.android.server.appsearch.external.localstorage.converter.SetSchemaResponseToProtoConverter; import com.android.server.appsearch.external.localstorage.converter.TypePropertyPathToProtoConverter; +import com.android.server.appsearch.external.localstorage.stats.InitializeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; +import com.android.server.appsearch.external.localstorage.stats.SearchStats; import com.google.android.icing.IcingSearchEngine; import com.google.android.icing.proto.DeleteByQueryResultProto; @@ -178,28 +180,63 @@ public final class AppSearchImpl implements Closeable { /** * Creates and initializes an instance of {@link AppSearchImpl} which writes data to the given * folder. + * + * <p>Clients can pass a {@link AppSearchLogger} here through their AppSearchSession, but it + * can't be saved inside {@link AppSearchImpl}, because the impl will be shared by all the + * sessions for the same package in JetPack. + * + * <p>Instead, logger instance needs to be passed to each individual method, like create, query + * and putDocument. + * + * @param logger collects stats for initialization if provided. */ @NonNull public static AppSearchImpl create( @NonNull File icingDir, @NonNull Context context, int userId, - @NonNull String globalQuerierPackage) + @NonNull String globalQuerierPackage, + @Nullable AppSearchLogger logger) throws AppSearchException { Objects.requireNonNull(icingDir); Objects.requireNonNull(context); Objects.requireNonNull(globalQuerierPackage); + + long totalLatencyStartMillis = SystemClock.elapsedRealtime(); + InitializeStats.Builder initStatsBuilder = null; + if (logger != null) { + initStatsBuilder = new InitializeStats.Builder(); + } + AppSearchImpl appSearchImpl = - new AppSearchImpl(icingDir, context, userId, globalQuerierPackage); + new AppSearchImpl( + icingDir, context, userId, globalQuerierPackage, initStatsBuilder); + + long prepareVisibilityStoreLatencyStartMillis = SystemClock.elapsedRealtime(); appSearchImpl.initializeVisibilityStore(); + long prepareVisibilityStoreLatencyEndMillis = SystemClock.elapsedRealtime(); + + if (logger != null && initStatsBuilder != null) { + initStatsBuilder + .setTotalLatencyMillis( + (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis)) + .setPrepareVisibilityStoreLatencyMillis( + (int) + (prepareVisibilityStoreLatencyEndMillis + - prepareVisibilityStoreLatencyStartMillis)); + logger.logStats(initStatsBuilder.build()); + } + return appSearchImpl; } + /** @param initStatsBuilder collects stats for initialization if provided. */ private AppSearchImpl( @NonNull File icingDir, @NonNull Context context, int userId, - @NonNull String globalQuerierPackage) + @NonNull String globalQuerierPackage, + @Nullable InitializeStats.Builder initStatsBuilder) throws AppSearchException { mReadWriteLock.writeLock().lock(); @@ -211,13 +248,24 @@ public final class AppSearchImpl implements Closeable { .setBaseDir(icingDir.getAbsolutePath()) .build(); mIcingSearchEngineLocked = new IcingSearchEngine(options); - mVisibilityStoreLocked = new VisibilityStore(this, context, userId, globalQuerierPackage); - InitializeResultProto initializeResultProto = mIcingSearchEngineLocked.initialize(); + + if (initStatsBuilder != null) { + initStatsBuilder + .setStatusCode( + statusProtoToAppSearchException(initializeResultProto.getStatus()) + .getResultCode()) + // TODO(b/173532925) how to get DeSyncs value + .setHasDeSync(false); + AppSearchLoggerHelper.copyNativeStats( + initializeResultProto.getInitializeStats(), initStatsBuilder); + } + + long prepareSchemaAndNamespacesLatencyStartMillis = SystemClock.elapsedRealtime(); SchemaProto schemaProto; - GetAllNamespacesResultProto getAllNamespacesResultProto; + GetAllNamespacesResultProto getAllNamespacesResultProto = null; try { checkSuccess(initializeResultProto.getStatus()); schemaProto = getSchemaProtoLocked(); @@ -225,6 +273,17 @@ public final class AppSearchImpl implements Closeable { checkSuccess(getAllNamespacesResultProto.getStatus()); } catch (AppSearchException e) { Log.w(TAG, "Error initializing, resetting IcingSearchEngine.", e); + if (initStatsBuilder != null && getAllNamespacesResultProto != null) { + initStatsBuilder + .setStatusCode( + statusProtoToAppSearchException( + getAllNamespacesResultProto.getStatus()) + .getResultCode()) + .setPrepareSchemaAndNamespacesLatencyMillis( + (int) + (SystemClock.elapsedRealtime() + - prepareSchemaAndNamespacesLatencyStartMillis)); + } // Some error. Reset and see if it fixes it. resetLocked(); return; @@ -240,6 +299,14 @@ public final class AppSearchImpl implements Closeable { for (String prefixedNamespace : getAllNamespacesResultProto.getNamespacesList()) { addToMap(mNamespaceMapLocked, getPrefix(prefixedNamespace), prefixedNamespace); } + + // logging prepare_schema_and_namespaces latency + if (initStatsBuilder != null) { + initStatsBuilder.setPrepareSchemaAndNamespacesLatencyMillis( + (int) + (SystemClock.elapsedRealtime() + - prepareSchemaAndNamespacesLatencyStartMillis)); + } } finally { mReadWriteLock.writeLock().unlock(); } @@ -539,7 +606,7 @@ public final class AppSearchImpl implements Closeable { addToMap(mNamespaceMapLocked, prefix, documentBuilder.getNamespace()); // Logging stats - if (logger != null) { + if (logger != null && pStatsBuilder != null) { pStatsBuilder .getGeneralStatsBuilder() .setStatusCode( @@ -562,7 +629,7 @@ public final class AppSearchImpl implements Closeable { } finally { mReadWriteLock.writeLock().unlock(); - if (logger != null) { + if (logger != null && pStatsBuilder != null) { long totalEndTimeMillis = SystemClock.elapsedRealtime(); pStatsBuilder .getGeneralStatsBuilder() @@ -644,6 +711,7 @@ public final class AppSearchImpl implements Closeable { * @param databaseName The databaseName this query for. * @param queryExpression Query String to search. * @param searchSpec Spec for setting filters, raw query etc. + * @param logger logger to collect query stats * @return The results of performing this search. It may contain an empty list of results if no * documents matched the query. * @throws AppSearchException on IcingSearchEngine error. @@ -653,8 +721,17 @@ public final class AppSearchImpl implements Closeable { @NonNull String packageName, @NonNull String databaseName, @NonNull String queryExpression, - @NonNull SearchSpec searchSpec) + @NonNull SearchSpec searchSpec, + @Nullable AppSearchLogger logger) throws AppSearchException { + long totalLatencyStartMillis = SystemClock.elapsedRealtime(); + SearchStats.Builder sStatsBuilder = null; + if (logger != null) { + sStatsBuilder = + new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_LOCAL, packageName) + .setDatabase(databaseName); + } + mReadWriteLock.readLock().lock(); try { throwIfClosedLocked(); @@ -673,9 +750,15 @@ public final class AppSearchImpl implements Closeable { Collections.singleton(createPrefix(packageName, databaseName)), allowedPrefixedSchemas, queryExpression, - searchSpec); + searchSpec, + sStatsBuilder); } finally { mReadWriteLock.readLock().unlock(); + if (logger != null && sStatsBuilder != null) { + sStatsBuilder.setTotalLatencyMillis( + (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis)); + logger.logStats(sStatsBuilder.build()); + } } } @@ -689,6 +772,7 @@ public final class AppSearchImpl implements Closeable { * @param searchSpec Spec for setting filters, raw query etc. * @param callerPackageName Package name of the caller, should belong to the {@code callerUid}. * @param callerUid UID of the client making the globalQuery call. + * @param logger logger to collect globalQuery stats * @return The results of performing this search. It may contain an empty list of results if no * documents matched the query. * @throws AppSearchException on IcingSearchEngine error. @@ -698,8 +782,16 @@ public final class AppSearchImpl implements Closeable { @NonNull String queryExpression, @NonNull SearchSpec searchSpec, @NonNull String callerPackageName, - int callerUid) + int callerUid, + @Nullable AppSearchLogger logger) throws AppSearchException { + long totalLatencyStartMillis = SystemClock.elapsedRealtime(); + SearchStats.Builder sStatsBuilder = null; + if (logger != null) { + sStatsBuilder = + new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_GLOBAL, callerPackageName); + } + mReadWriteLock.readLock().lock(); try { throwIfClosedLocked(); @@ -754,9 +846,19 @@ public final class AppSearchImpl implements Closeable { } return doQueryLocked( - prefixFilters, allowedPrefixedSchemas, queryExpression, searchSpec); + prefixFilters, + allowedPrefixedSchemas, + queryExpression, + searchSpec, + sStatsBuilder); } finally { mReadWriteLock.readLock().unlock(); + + if (logger != null && sStatsBuilder != null) { + sStatsBuilder.setTotalLatencyMillis( + (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis)); + logger.logStats(sStatsBuilder.build()); + } } } @@ -794,8 +896,11 @@ public final class AppSearchImpl implements Closeable { @NonNull Set<String> prefixes, @NonNull Set<String> allowedPrefixedSchemas, @NonNull String queryExpression, - @NonNull SearchSpec searchSpec) + @NonNull SearchSpec searchSpec, + @Nullable SearchStats.Builder sStatsBuilder) throws AppSearchException { + long rewriteSearchSpecLatencyStartMillis = SystemClock.elapsedRealtime(); + SearchSpecProto.Builder searchSpecBuilder = SearchSpecToProtoConverter.toSearchSpecProto(searchSpec).toBuilder() .setQuery(queryExpression); @@ -804,9 +909,17 @@ public final class AppSearchImpl implements Closeable { // sending request to Icing. if (!rewriteSearchSpecForPrefixesLocked( searchSpecBuilder, prefixes, allowedPrefixedSchemas)) { + if (sStatsBuilder != null) { + sStatsBuilder.setRewriteSearchSpecLatencyMillis( + (int) + (SystemClock.elapsedRealtime() + - rewriteSearchSpecLatencyStartMillis)); + } return new SearchResultPage(Bundle.EMPTY); } + // rewriteSearchSpec, rewriteResultSpec and convertScoringSpec are all counted in + // rewriteSearchSpecLatencyMillis ResultSpecProto.Builder resultSpecBuilder = SearchSpecToProtoConverter.toResultSpecProto(searchSpec).toBuilder(); @@ -822,15 +935,38 @@ public final class AppSearchImpl implements Closeable { addPerNamespaceResultGroupingsLocked( resultSpecBuilder, prefixes, searchSpec.getResultGroupingLimit()); } - rewriteResultSpecForPrefixesLocked(resultSpecBuilder, prefixes, allowedPrefixedSchemas); + rewriteResultSpecForPrefixesLocked(resultSpecBuilder, prefixes, allowedPrefixedSchemas); ScoringSpecProto scoringSpec = SearchSpecToProtoConverter.toScoringSpecProto(searchSpec); + + long rewriteSearchSpecLatencyEndMillis = SystemClock.elapsedRealtime(); + SearchResultProto searchResultProto = mIcingSearchEngineLocked.search( searchSpecBuilder.build(), scoringSpec, resultSpecBuilder.build()); + + if (sStatsBuilder != null) { + sStatsBuilder + .setStatusCode( + statusProtoToAppSearchException(searchResultProto.getStatus()) + .getResultCode()) + .setRewriteSearchSpecLatencyMillis( + (int) + (rewriteSearchSpecLatencyEndMillis + - rewriteSearchSpecLatencyStartMillis)); + AppSearchLoggerHelper.copyNativeStats(searchResultProto.getQueryStats(), sStatsBuilder); + } + checkSuccess(searchResultProto.getStatus()); - return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked); + long rewriteSearchResultLatencyStartMillis = SystemClock.elapsedRealtime(); + SearchResultPage resultPage = rewriteSearchResultProto(searchResultProto, mSchemaMapLocked); + if (sStatsBuilder != null) { + sStatsBuilder.setRewriteSearchResultLatencyMillis( + (int) (SystemClock.elapsedRealtime() - rewriteSearchResultLatencyStartMillis)); + } + + return resultPage; } /** diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java index 0f23d926648b..97c886922c32 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java @@ -20,7 +20,9 @@ import android.annotation.NonNull; import android.app.appsearch.exceptions.AppSearchException; import com.android.server.appsearch.external.localstorage.stats.CallStats; +import com.android.server.appsearch.external.localstorage.stats.InitializeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; +import com.android.server.appsearch.external.localstorage.stats.SearchStats; /** * An interface for implementing client-defined logging AppSearch operations stats. @@ -39,5 +41,11 @@ public interface AppSearchLogger { /** Logs {@link PutDocumentStats} */ void logStats(@NonNull PutDocumentStats stats) throws AppSearchException; + /** Logs {@link InitializeStats} */ + void logStats(@NonNull InitializeStats stats) throws AppSearchException; + + /** Logs {@link SearchStats} */ + void logStats(@NonNull SearchStats stats) throws AppSearchException; + // TODO(b/173532925) Add remaining logStats once we add all the stats. } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java index cdd795207e0b..4a5ecf1bc0b9 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java @@ -18,9 +18,13 @@ package com.android.server.appsearch.external.localstorage; import android.annotation.NonNull; +import com.android.server.appsearch.external.localstorage.stats.InitializeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; +import com.android.server.appsearch.external.localstorage.stats.SearchStats; +import com.google.android.icing.proto.InitializeStatsProto; import com.google.android.icing.proto.PutDocumentStatsProto; +import com.google.android.icing.proto.QueryStatsProto; import java.util.Objects; @@ -35,7 +39,7 @@ public final class AppSearchLoggerHelper { private AppSearchLoggerHelper() {} /** - * Copies native stats to builder. + * Copies native PutDocument stats to builder. * * @param fromNativeStats stats copied from * @param toStatsBuilder stats copied to @@ -56,4 +60,64 @@ public final class AppSearchLoggerHelper { .setNativeExceededMaxNumTokens( fromNativeStats.getTokenizationStats().getExceededMaxTokenNum()); } + + /** + * Copies native Initialize stats to builder. + * + * @param fromNativeStats stats copied from + * @param toStatsBuilder stats copied to + */ + static void copyNativeStats( + @NonNull InitializeStatsProto fromNativeStats, + @NonNull InitializeStats.Builder toStatsBuilder) { + Objects.requireNonNull(fromNativeStats); + Objects.requireNonNull(toStatsBuilder); + toStatsBuilder + .setNativeLatencyMillis(fromNativeStats.getLatencyMs()) + .setDocumentStoreRecoveryCause( + fromNativeStats.getDocumentStoreRecoveryCause().getNumber()) + .setIndexRestorationCause(fromNativeStats.getIndexRestorationCause().getNumber()) + .setSchemaStoreRecoveryCause( + fromNativeStats.getSchemaStoreRecoveryCause().getNumber()) + .setDocumentStoreRecoveryLatencyMillis( + fromNativeStats.getDocumentStoreRecoveryLatencyMs()) + .setIndexRestorationLatencyMillis(fromNativeStats.getIndexRestorationLatencyMs()) + .setSchemaStoreRecoveryLatencyMillis( + fromNativeStats.getSchemaStoreRecoveryLatencyMs()) + .setDocumentStoreDataStatus( + fromNativeStats.getDocumentStoreDataStatus().getNumber()) + .setDocumentCount(fromNativeStats.getNumDocuments()) + .setSchemaTypeCount(fromNativeStats.getNumSchemaTypes()); + } + + /* + * Copy native Query stats to buiilder. + * + * @param fromNativeStats Stats copied from. + * @param toStatsBuilder Stats copied to. + */ + static void copyNativeStats( + @NonNull QueryStatsProto fromNativeStats, @NonNull SearchStats.Builder toStatsBuilder) { + Objects.requireNonNull(fromNativeStats); + Objects.requireNonNull(toStatsBuilder); + toStatsBuilder + .setNativeLatencyMillis(fromNativeStats.getLatencyMs()) + .setTermCount(fromNativeStats.getNumTerms()) + // TODO(b/173532925) query length missing in native + // .setNativeQueryLength(0) + .setFilteredNamespaceCount(fromNativeStats.getNumNamespacesFiltered()) + .setFilteredSchemaTypeCount(fromNativeStats.getNumSchemaTypesFiltered()) + .setRequestedPageSize(fromNativeStats.getRequestedPageSize()) + .setCurrentPageReturnedResultCount( + fromNativeStats.getNumResultsReturnedCurrentPage()) + .setIsFirstPage(fromNativeStats.getIsFirstPage()) + .setParseQueryLatencyMillis(fromNativeStats.getParseQueryLatencyMs()) + .setRankingStrategy(fromNativeStats.getRankingStrategy().getNumber()) + .setScoredDocumentCount(fromNativeStats.getNumDocumentsScored()) + .setScoringLatencyMillis(fromNativeStats.getScoringLatencyMs()) + .setRankingLatencyMillis(fromNativeStats.getRankingLatencyMs()) + .setResultWithSnippetsCount(fromNativeStats.getNumResultsWithSnippets()) + .setDocumentRetrievingLatencyMillis( + fromNativeStats.getDocumentRetrievalLatencyMs()); + } } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/InitializeStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/InitializeStats.java new file mode 100644 index 000000000000..5364a0caa1aa --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/InitializeStats.java @@ -0,0 +1,404 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appsearch.external.localstorage.stats; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.app.appsearch.AppSearchResult; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Class holds detailed stats for initialization + * + * @hide + */ +public final class InitializeStats { + /** + * The cause of IcingSearchEngine recovering from a previous bad state during initialization. + */ + @IntDef( + value = { + // It needs to be sync with RecoveryCause in + // external/icing/proto/icing/proto/logging.proto#InitializeStatsProto + RECOVERY_CAUSE_NONE, + RECOVERY_CAUSE_DATA_LOSS, + RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH, + RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH, + RECOVERY_CAUSE_IO_ERROR, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface RecoveryCause {} + + // No recovery happened. + public static final int RECOVERY_CAUSE_NONE = 0; + // Data loss in ground truth. + public static final int RECOVERY_CAUSE_DATA_LOSS = 1; + // Data in index is inconsistent with ground truth. + public static final int RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH = 2; + // Total checksum of all the components does not match. + public static final int RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH = 3; + // Random I/O errors. + public static final int RECOVERY_CAUSE_IO_ERROR = 4; + + /** Status regarding how much data is lost during the initialization. */ + @IntDef( + value = { + // It needs to be sync with DocumentStoreDataStatus in + // external/icing/proto/icing/proto/logging.proto#InitializeStatsProto + + DOCUMENT_STORE_DATA_STATUS_NO_DATA_LOSS, + DOCUMENT_STORE_DATA_STATUS_PARTIAL_LOSS, + DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DocumentStoreDataStatus {} + + // Document store is successfully initialized or fully recovered. + public static final int DOCUMENT_STORE_DATA_STATUS_NO_DATA_LOSS = 0; + // Ground truth data is partially lost. + public static final int DOCUMENT_STORE_DATA_STATUS_PARTIAL_LOSS = 1; + // Ground truth data is completely lost. + public static final int DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS = 2; + + @AppSearchResult.ResultCode private final int mStatusCode; + private final int mTotalLatencyMillis; + /** Whether the initialize() detects deSync. */ + private final boolean mHasDeSync; + /** Time used to read and process the schema and namespaces. */ + private final int mPrepareSchemaAndNamespacesLatencyMillis; + /** Time used to read and process the visibility store. */ + private final int mPrepareVisibilityStoreLatencyMillis; + /** Overall time used for the native function call. */ + private final int mNativeLatencyMillis; + + @RecoveryCause private final int mNativeDocumentStoreRecoveryCause; + @RecoveryCause private final int mNativeIndexRestorationCause; + @RecoveryCause private final int mNativeSchemaStoreRecoveryCause; + /** Time used to recover the document store. */ + private final int mNativeDocumentStoreRecoveryLatencyMillis; + /** Time used to restore the index. */ + private final int mNativeIndexRestorationLatencyMillis; + /** Time used to recover the schema store. */ + private final int mNativeSchemaStoreRecoveryLatencyMillis; + /** Status regarding how much data is lost during the initialization. */ + private final int mNativeDocumentStoreDataStatus; + /** + * Returns number of documents currently in document store. Those may include alive, deleted, + * and expired documents. + */ + private final int mNativeNumDocuments; + /** Returns number of schema types currently in the schema store. */ + private final int mNativeNumSchemaTypes; + + /** Returns the status of the initialization. */ + @AppSearchResult.ResultCode + public int getStatusCode() { + return mStatusCode; + } + + /** Returns the total latency in milliseconds for the initialization. */ + public int getTotalLatencyMillis() { + return mTotalLatencyMillis; + } + + /** + * Returns whether the initialize() detects deSync. + * + * <p>If there is a deSync, it means AppSearch and IcingSearchEngine have an inconsistent view + * of what data should exist. + */ + public boolean hasDeSync() { + return mHasDeSync; + } + + /** Returns time used to read and process the schema and namespaces. */ + public int getPrepareSchemaAndNamespacesLatencyMillis() { + return mPrepareSchemaAndNamespacesLatencyMillis; + } + + /** Returns time used to read and process the visibility file. */ + public int getPrepareVisibilityStoreLatencyMillis() { + return mPrepareVisibilityStoreLatencyMillis; + } + + /** Returns overall time used for the native function call. */ + public int getNativeLatencyMillis() { + return mNativeLatencyMillis; + } + + /** + * Returns recovery cause for document store. + * + * <p>Possible recovery causes for document store: + * <li>{@link InitializeStats#RECOVERY_CAUSE_DATA_LOSS} + * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH} + * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR} + */ + @RecoveryCause + public int getDocumentStoreRecoveryCause() { + return mNativeDocumentStoreRecoveryCause; + } + + /** + * Returns restoration cause for index store. + * + * <p>Possible causes: + * <li>{@link InitializeStats#RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH} + * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH} + * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR} + */ + @RecoveryCause + public int getIndexRestorationCause() { + return mNativeIndexRestorationCause; + } + + /** + * Returns recovery cause for schema store. + * + * <p>Possible causes: + * <li>IO_ERROR + */ + @RecoveryCause + public int getSchemaStoreRecoveryCause() { + return mNativeSchemaStoreRecoveryCause; + } + + /** Returns time used to recover the document store. */ + public int getDocumentStoreRecoveryLatencyMillis() { + return mNativeDocumentStoreRecoveryLatencyMillis; + } + + /** Returns time used to restore the index. */ + public int getIndexRestorationLatencyMillis() { + return mNativeIndexRestorationLatencyMillis; + } + + /** Returns time used to recover the schema store. */ + public int getSchemaStoreRecoveryLatencyMillis() { + return mNativeSchemaStoreRecoveryLatencyMillis; + } + + /** Returns status about how much data is lost during the initialization. */ + @DocumentStoreDataStatus + public int getDocumentStoreDataStatus() { + return mNativeDocumentStoreDataStatus; + } + + /** + * Returns number of documents currently in document store. Those may include alive, deleted, + * and expired documents. + */ + public int getDocumentCount() { + return mNativeNumDocuments; + } + + /** Returns number of schema types currently in the schema store. */ + public int getSchemaTypeCount() { + return mNativeNumSchemaTypes; + } + + InitializeStats(@NonNull Builder builder) { + Objects.requireNonNull(builder); + mStatusCode = builder.mStatusCode; + mTotalLatencyMillis = builder.mTotalLatencyMillis; + mHasDeSync = builder.mHasDeSync; + mPrepareSchemaAndNamespacesLatencyMillis = builder.mPrepareSchemaAndNamespacesLatencyMillis; + mPrepareVisibilityStoreLatencyMillis = builder.mPrepareVisibilityStoreLatencyMillis; + mNativeLatencyMillis = builder.mNativeLatencyMillis; + mNativeDocumentStoreRecoveryCause = builder.mNativeDocumentStoreRecoveryCause; + mNativeIndexRestorationCause = builder.mNativeIndexRestorationCause; + mNativeSchemaStoreRecoveryCause = builder.mNativeSchemaStoreRecoveryCause; + mNativeDocumentStoreRecoveryLatencyMillis = + builder.mNativeDocumentStoreRecoveryLatencyMillis; + mNativeIndexRestorationLatencyMillis = builder.mNativeIndexRestorationLatencyMillis; + mNativeSchemaStoreRecoveryLatencyMillis = builder.mNativeSchemaStoreRecoveryLatencyMillis; + mNativeDocumentStoreDataStatus = builder.mNativeDocumentStoreDataStatus; + mNativeNumDocuments = builder.mNativeNumDocuments; + mNativeNumSchemaTypes = builder.mNativeNumSchemaTypes; + } + + /** Builder for {@link InitializeStats}. */ + public static class Builder { + @AppSearchResult.ResultCode int mStatusCode; + int mTotalLatencyMillis; + boolean mHasDeSync; + int mPrepareSchemaAndNamespacesLatencyMillis; + int mPrepareVisibilityStoreLatencyMillis; + int mNativeLatencyMillis; + @RecoveryCause int mNativeDocumentStoreRecoveryCause; + @RecoveryCause int mNativeIndexRestorationCause; + @RecoveryCause int mNativeSchemaStoreRecoveryCause; + int mNativeDocumentStoreRecoveryLatencyMillis; + int mNativeIndexRestorationLatencyMillis; + int mNativeSchemaStoreRecoveryLatencyMillis; + @DocumentStoreDataStatus int mNativeDocumentStoreDataStatus; + int mNativeNumDocuments; + int mNativeNumSchemaTypes; + + /** Sets the status of the initialization. */ + @NonNull + public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) { + mStatusCode = statusCode; + return this; + } + + /** Sets the total latency of the initialization in milliseconds. */ + @NonNull + public Builder setTotalLatencyMillis(int totalLatencyMillis) { + mTotalLatencyMillis = totalLatencyMillis; + return this; + } + + /** + * Sets whether the initialize() detects deSync. + * + * <p>If there is a deSync, it means AppSearch and IcingSearchEngine have an inconsistent + * view of what data should exist. + */ + @NonNull + public Builder setHasDeSync(boolean hasDeSync) { + mHasDeSync = hasDeSync; + return this; + } + + /** Sets time used to read and process the schema and namespaces. */ + @NonNull + public Builder setPrepareSchemaAndNamespacesLatencyMillis( + int prepareSchemaAndNamespacesLatencyMillis) { + mPrepareSchemaAndNamespacesLatencyMillis = prepareSchemaAndNamespacesLatencyMillis; + return this; + } + + /** Sets time used to read and process the visibility file. */ + @NonNull + public Builder setPrepareVisibilityStoreLatencyMillis( + int prepareVisibilityStoreLatencyMillis) { + mPrepareVisibilityStoreLatencyMillis = prepareVisibilityStoreLatencyMillis; + return this; + } + + /** Sets overall time used for the native function call. */ + @NonNull + public Builder setNativeLatencyMillis(int nativeLatencyMillis) { + mNativeLatencyMillis = nativeLatencyMillis; + return this; + } + + /** + * Sets recovery cause for document store. + * + * <p>Possible recovery causes for document store: + * <li>{@link InitializeStats#RECOVERY_CAUSE_DATA_LOSS} + * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH} + * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR} + */ + @NonNull + public Builder setDocumentStoreRecoveryCause( + @RecoveryCause int documentStoreRecoveryCause) { + mNativeDocumentStoreRecoveryCause = documentStoreRecoveryCause; + return this; + } + + /** + * Sets restoration cause for index store. + * + * <p>Possible causes: + * <li>{@link InitializeStats#DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS} + * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH} + * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR} + */ + @NonNull + public Builder setIndexRestorationCause(@RecoveryCause int indexRestorationCause) { + mNativeIndexRestorationCause = indexRestorationCause; + return this; + } + + /** + * Returns recovery cause for schema store. + * + * <p>Possible causes: + * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR} + */ + @NonNull + public Builder setSchemaStoreRecoveryCause(@RecoveryCause int schemaStoreRecoveryCause) { + mNativeSchemaStoreRecoveryCause = schemaStoreRecoveryCause; + return this; + } + + /** Sets time used to recover the document store. */ + @NonNull + public Builder setDocumentStoreRecoveryLatencyMillis( + int documentStoreRecoveryLatencyMillis) { + mNativeDocumentStoreRecoveryLatencyMillis = documentStoreRecoveryLatencyMillis; + return this; + } + + /** Sets time used to restore the index. */ + @NonNull + public Builder setIndexRestorationLatencyMillis(int indexRestorationLatencyMillis) { + mNativeIndexRestorationLatencyMillis = indexRestorationLatencyMillis; + return this; + } + + /** Sets time used to recover the schema store. */ + @NonNull + public Builder setSchemaStoreRecoveryLatencyMillis(int schemaStoreRecoveryLatencyMillis) { + mNativeSchemaStoreRecoveryLatencyMillis = schemaStoreRecoveryLatencyMillis; + return this; + } + + /** + * Sets Native Document Store Data status. status is defined in + * external/icing/proto/icing/proto/logging.proto + */ + @NonNull + public Builder setDocumentStoreDataStatus( + @DocumentStoreDataStatus int documentStoreDataStatus) { + mNativeDocumentStoreDataStatus = documentStoreDataStatus; + return this; + } + + /** + * Sets number of documents currently in document store. Those may include alive, deleted, + * and expired documents. + */ + @NonNull + public Builder setDocumentCount(int numDocuments) { + mNativeNumDocuments = numDocuments; + return this; + } + + /** Sets number of schema types currently in the schema store. */ + @NonNull + public Builder setSchemaTypeCount(int numSchemaTypes) { + mNativeNumSchemaTypes = numSchemaTypes; + return this; + } + + /** + * Constructs a new {@link InitializeStats} from the contents of this {@link + * InitializeStats.Builder} + */ + @NonNull + public InitializeStats build() { + return new InitializeStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java new file mode 100644 index 000000000000..7b22b2f23142 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java @@ -0,0 +1,460 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.appsearch.external.localstorage.stats; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.appsearch.AppSearchResult; +import android.app.appsearch.SearchSpec; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Class holds detailed stats for {@link android.app.appsearch.AppSearchSession#search(String, + * SearchSpec)} + * + * @hide + */ +public final class SearchStats { + @IntDef( + value = { + // Searches apps' own documents. + VISIBILITY_SCOPE_LOCAL, + // Searches the global documents. Including platform surfaceable and 3p-access. + VISIBILITY_SCOPE_GLOBAL, + // TODO(b/173532925) Add THIRD_PARTY_ACCESS once we can distinguish platform + // surfaceable from 3p access(right both of them are categorized as + // VISIBILITY_SCOPE_GLOBAL) + }) + @Retention(RetentionPolicy.SOURCE) + public @interface VisibilityScope {} + + // Searches apps' own documents. + public static final int VISIBILITY_SCOPE_LOCAL = 1; + // Searches the global documents. Including platform surfaceable and 3p-access. + public static final int VISIBILITY_SCOPE_GLOBAL = 2; + + @NonNull private final String mPackageName; + @Nullable private final String mDatabase; + /** + * The status code returned by {@link AppSearchResult#getResultCode()} for the call or internal + * state. + */ + @AppSearchResult.ResultCode private final int mStatusCode; + + private final int mTotalLatencyMillis; + /** Time used to rewrite the search spec. */ + private final int mRewriteSearchSpecLatencyMillis; + /** Time used to rewrite the search results. */ + private final int mRewriteSearchResultLatencyMillis; + /** Defines the scope the query is searching over */ + @VisibilityScope private final int mVisibilityScope; + /** Overall time used for the native function call. */ + private final int mNativeLatencyMillis; + /** Number of terms in the query string. */ + private final int mNativeNumTerms; + /** Length of the query string. */ + private final int mNativeQueryLength; + /** Number of namespaces filtered. */ + private final int mNativeNumNamespacesFiltered; + /** Number of schema types filtered. */ + private final int mNativeNumSchemaTypesFiltered; + /** The requested number of results in one page. */ + private final int mNativeRequestedPageSize; + /** The actual number of results returned in the current page. */ + private final int mNativeNumResultsReturnedCurrentPage; + /** + * Whether the function call is querying the first page. If it's not, Icing will fetch the + * results from cache so that some steps may be skipped. + */ + private final boolean mNativeIsFirstPage; + /** + * Time used to parse the query, including 2 parts: tokenizing and transforming tokens into an + * iterator tree. + */ + private final int mNativeParseQueryLatencyMillis; + /** Strategy of scoring and ranking. */ + @SearchSpec.RankingStrategy private final int mNativeRankingStrategy; + /** Number of documents scored. */ + private final int mNativeNumDocumentsScored; + /** Time used to score the raw results. */ + private final int mNativeScoringLatencyMillis; + /** Time used to rank the scored results. */ + private final int mNativeRankingLatencyMillis; + /** + * Time used to fetch the document protos. Note that it includes the time to snippet if {@link + * SearchStats#mNativeNumResultsWithSnippets} is greater than 0. + */ + private final int mNativeDocumentRetrievingLatencyMillis; + /** How many snippets are calculated. */ + private final int mNativeNumResultsWithSnippets; + + SearchStats(@NonNull Builder builder) { + Objects.requireNonNull(builder); + mPackageName = builder.mPackageName; + mDatabase = builder.mDatabase; + mStatusCode = builder.mStatusCode; + mTotalLatencyMillis = builder.mTotalLatencyMillis; + mRewriteSearchSpecLatencyMillis = builder.mRewriteSearchSpecLatencyMillis; + mRewriteSearchResultLatencyMillis = builder.mRewriteSearchResultLatencyMillis; + mVisibilityScope = builder.mVisibilityScope; + mNativeLatencyMillis = builder.mNativeLatencyMillis; + mNativeNumTerms = builder.mNativeNumTerms; + mNativeQueryLength = builder.mNativeQueryLength; + mNativeNumNamespacesFiltered = builder.mNativeNumNamespacesFiltered; + mNativeNumSchemaTypesFiltered = builder.mNativeNumSchemaTypesFiltered; + mNativeRequestedPageSize = builder.mNativeRequestedPageSize; + mNativeNumResultsReturnedCurrentPage = builder.mNativeNumResultsReturnedCurrentPage; + mNativeIsFirstPage = builder.mNativeIsFirstPage; + mNativeParseQueryLatencyMillis = builder.mNativeParseQueryLatencyMillis; + mNativeRankingStrategy = builder.mNativeRankingStrategy; + mNativeNumDocumentsScored = builder.mNativeNumDocumentsScored; + mNativeScoringLatencyMillis = builder.mNativeScoringLatencyMillis; + mNativeRankingLatencyMillis = builder.mNativeRankingLatencyMillis; + mNativeNumResultsWithSnippets = builder.mNativeNumResultsWithSnippets; + mNativeDocumentRetrievingLatencyMillis = builder.mNativeDocumentRetrievingLatencyMillis; + } + + /** Returns the package name of the session. */ + @NonNull + public String getPackageName() { + return mPackageName; + } + + /** + * Returns the database name of the session. + * + * @return database name used by the session. {@code null} if and only if it is a global + * search(visibilityScope is {@link SearchStats#VISIBILITY_SCOPE_GLOBAL}). + */ + @Nullable + public String getDatabase() { + return mDatabase; + } + + /** Returns status of the search. */ + @AppSearchResult.ResultCode + public int getStatusCode() { + return mStatusCode; + } + + /** Returns the total latency of the search. */ + public int getTotalLatencyMillis() { + return mTotalLatencyMillis; + } + + /** Returns how much time spent on rewriting the {@link SearchSpec}. */ + public int getRewriteSearchSpecLatencyMillis() { + return mRewriteSearchSpecLatencyMillis; + } + + /** Returns how much time spent on rewriting the {@link android.app.appsearch.SearchResult}. */ + public int getRewriteSearchResultLatencyMillis() { + return mRewriteSearchResultLatencyMillis; + } + + /** Returns the visibility scope of the search. */ + @VisibilityScope + public int getVisibilityScope() { + return mVisibilityScope; + } + + /** Returns how much time spent on the native calls. */ + public int getNativeLatencyMillis() { + return mNativeLatencyMillis; + } + + /** Returns number of terms in the search string. */ + public int getTermCount() { + return mNativeNumTerms; + } + + /** Returns the length of the search string. */ + public int getQueryLength() { + return mNativeQueryLength; + } + + /** Returns number of namespaces filtered. */ + public int getFilteredNamespaceCount() { + return mNativeNumNamespacesFiltered; + } + + /** Returns number of schema types filtered. */ + public int getFilteredSchemaTypeCount() { + return mNativeNumSchemaTypesFiltered; + } + + /** Returns the requested number of results in one page. */ + public int getRequestedPageSize() { + return mNativeRequestedPageSize; + } + + /** Returns the actual number of results returned in the current page. */ + public int getCurrentPageReturnedResultCount() { + return mNativeNumResultsReturnedCurrentPage; + } + + // TODO(b/185184738) Make it an integer to show how many pages having been returned. + /** Returns whether the function call is querying the first page. */ + public boolean isFirstPage() { + return mNativeIsFirstPage; + } + + /** + * Returns time used to parse the query, including 2 parts: tokenizing and transforming tokens + * into an iterator tree. + */ + public int getParseQueryLatencyMillis() { + return mNativeParseQueryLatencyMillis; + } + + /** Returns strategy of scoring and ranking. */ + @SearchSpec.RankingStrategy + public int getRankingStrategy() { + return mNativeRankingStrategy; + } + + /** Returns number of documents scored. */ + public int getScoredDocumentCount() { + return mNativeNumDocumentsScored; + } + + /** Returns time used to score the raw results. */ + public int getScoringLatencyMillis() { + return mNativeScoringLatencyMillis; + } + + /** Returns time used to rank the scored results. */ + public int getRankingLatencyMillis() { + return mNativeRankingLatencyMillis; + } + + /** + * Returns time used to fetch the document protos. Note that it includes the time to snippet if + * {@link SearchStats#mNativeNumResultsWithSnippets} is not zero. + */ + public int getDocumentRetrievingLatencyMillis() { + return mNativeDocumentRetrievingLatencyMillis; + } + + /** Returns the number of the results in the page returned were snippeted. */ + public int getResultWithSnippetsCount() { + return mNativeNumResultsWithSnippets; + } + + /** Builder for {@link SearchStats} */ + public static class Builder { + @NonNull final String mPackageName; + @Nullable String mDatabase; + @AppSearchResult.ResultCode int mStatusCode; + int mTotalLatencyMillis; + int mRewriteSearchSpecLatencyMillis; + int mRewriteSearchResultLatencyMillis; + int mVisibilityScope; + int mNativeLatencyMillis; + int mNativeNumTerms; + int mNativeQueryLength; + int mNativeNumNamespacesFiltered; + int mNativeNumSchemaTypesFiltered; + int mNativeRequestedPageSize; + int mNativeNumResultsReturnedCurrentPage; + boolean mNativeIsFirstPage; + int mNativeParseQueryLatencyMillis; + int mNativeRankingStrategy; + int mNativeNumDocumentsScored; + int mNativeScoringLatencyMillis; + int mNativeRankingLatencyMillis; + int mNativeNumResultsWithSnippets; + int mNativeDocumentRetrievingLatencyMillis; + + /** + * Constructor + * + * @param visibilityScope scope for the corresponding search. + * @param packageName name of the calling package. + */ + public Builder(@VisibilityScope int visibilityScope, @NonNull String packageName) { + mVisibilityScope = visibilityScope; + mPackageName = Objects.requireNonNull(packageName); + } + + /** Sets the database used by the session. */ + @NonNull + public Builder setDatabase(@NonNull String database) { + mDatabase = Objects.requireNonNull(database); + return this; + } + + /** Sets the status of the search. */ + @NonNull + public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) { + mStatusCode = statusCode; + return this; + } + + /** Sets total latency for the search. */ + @NonNull + public Builder setTotalLatencyMillis(int totalLatencyMillis) { + mTotalLatencyMillis = totalLatencyMillis; + return this; + } + + /** Sets time used to rewrite the search spec. */ + @NonNull + public Builder setRewriteSearchSpecLatencyMillis(int rewriteSearchSpecLatencyMillis) { + mRewriteSearchSpecLatencyMillis = rewriteSearchSpecLatencyMillis; + return this; + } + + /** Sets time used to rewrite the search results. */ + @NonNull + public Builder setRewriteSearchResultLatencyMillis(int rewriteSearchResultLatencyMillis) { + mRewriteSearchResultLatencyMillis = rewriteSearchResultLatencyMillis; + return this; + } + + /** Sets overall time used for the native function calls. */ + @NonNull + public Builder setNativeLatencyMillis(int nativeLatencyMillis) { + mNativeLatencyMillis = nativeLatencyMillis; + return this; + } + + /** Sets number of terms in the search string. */ + @NonNull + public Builder setTermCount(int termCount) { + mNativeNumTerms = termCount; + return this; + } + + /** Sets length of the search string. */ + @NonNull + public Builder setQueryLength(int queryLength) { + mNativeQueryLength = queryLength; + return this; + } + + /** Sets number of namespaces filtered. */ + @NonNull + public Builder setFilteredNamespaceCount(int filteredNamespaceCount) { + mNativeNumNamespacesFiltered = filteredNamespaceCount; + return this; + } + + /** Sets number of schema types filtered. */ + @NonNull + public Builder setFilteredSchemaTypeCount(int filteredSchemaTypeCount) { + mNativeNumSchemaTypesFiltered = filteredSchemaTypeCount; + return this; + } + + /** Sets the requested number of results in one page. */ + @NonNull + public Builder setRequestedPageSize(int requestedPageSize) { + mNativeRequestedPageSize = requestedPageSize; + return this; + } + + /** Sets the actual number of results returned in the current page. */ + @NonNull + public Builder setCurrentPageReturnedResultCount(int currentPageReturnedResultCount) { + mNativeNumResultsReturnedCurrentPage = currentPageReturnedResultCount; + return this; + } + + /** + * Sets whether the function call is querying the first page. If it's not, Icing will fetch + * the results from cache so that some steps may be skipped. + */ + @NonNull + public Builder setIsFirstPage(boolean nativeIsFirstPage) { + mNativeIsFirstPage = nativeIsFirstPage; + return this; + } + + /** + * Sets time used to parse the query, including 2 parts: tokenizing and transforming tokens + * into an iterator tree. + */ + @NonNull + public Builder setParseQueryLatencyMillis(int parseQueryLatencyMillis) { + mNativeParseQueryLatencyMillis = parseQueryLatencyMillis; + return this; + } + + /** Sets strategy of scoring and ranking. */ + @NonNull + public Builder setRankingStrategy(@SearchSpec.RankingStrategy int rankingStrategy) { + mNativeRankingStrategy = rankingStrategy; + return this; + } + + /** Sets number of documents scored. */ + @NonNull + public Builder setScoredDocumentCount(int scoredDocumentCount) { + mNativeNumDocumentsScored = scoredDocumentCount; + return this; + } + + /** Sets time used to score the raw results. */ + @NonNull + public Builder setScoringLatencyMillis(int scoringLatencyMillis) { + mNativeScoringLatencyMillis = scoringLatencyMillis; + return this; + } + + /** Sets time used to rank the scored results. */ + @NonNull + public Builder setRankingLatencyMillis(int rankingLatencyMillis) { + mNativeRankingLatencyMillis = rankingLatencyMillis; + return this; + } + + /** Sets time used to fetch the document protos. */ + @NonNull + public Builder setDocumentRetrievingLatencyMillis(int documentRetrievingLatencyMillis) { + mNativeDocumentRetrievingLatencyMillis = documentRetrievingLatencyMillis; + return this; + } + + /** Sets how many snippets are calculated. */ + @NonNull + public Builder setResultWithSnippetsCount(int resultWithSnippetsCount) { + mNativeNumResultsWithSnippets = resultWithSnippetsCount; + return this; + } + + /** + * Constructs a new {@link SearchStats} from the contents of this {@link + * SearchStats.Builder}. + */ + @NonNull + public SearchStats build() { + if (mDatabase == null) { + Preconditions.checkState( + mVisibilityScope != SearchStats.VISIBILITY_SCOPE_LOCAL, + "database can not be null if visibilityScope is local."); + } + + return new SearchStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java index 731ab35bf367..88f238e91e45 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java @@ -31,7 +31,9 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.server.appsearch.external.localstorage.AppSearchLogger; import com.android.server.appsearch.external.localstorage.stats.CallStats; +import com.android.server.appsearch.external.localstorage.stats.InitializeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; +import com.android.server.appsearch.external.localstorage.stats.SearchStats; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; @@ -189,6 +191,16 @@ public final class PlatformLogger implements AppSearchLogger { } } + @Override + public void logStats(@NonNull InitializeStats stats) throws AppSearchException { + // TODO(b/173532925): Implement + } + + @Override + public void logStats(@NonNull SearchStats stats) throws AppSearchException { + // TODO(b/173532925): Implement + } + /** * Removes cached UID for package. * diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt index ce0ebe62f65b..10bba13a8e2f 100644 --- a/apex/appsearch/synced_jetpack_changeid.txt +++ b/apex/appsearch/synced_jetpack_changeid.txt @@ -1 +1 @@ -I06df2c636d26419e653c5d8c9e7d15449da6816e +I19dac52031c47099f621eced9f148931f1021f25 diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java index 57293856a9ad..17682a5b655a 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java @@ -1513,6 +1513,11 @@ public class JobInfo implements Parcelable { * available quota (and the job will not be successfully scheduled). * * <p> + * Expedited job quota will replenish over time and as the user interacts with the app, + * so you should not have to worry about running out of quota because of processing from + * frequent user engagement. + * + * <p> * Expedited jobs may only set network, storage-not-low, and persistence constraints. * No other constraints are allowed. * diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java index 48b62a607a5e..32655c7c5ed1 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java @@ -45,25 +45,25 @@ public class JobParameters implements Parcelable { /** @hide */ public static final int INTERNAL_STOP_REASON_CANCELED = - JobProtoEnums.STOP_REASON_CANCELLED; // 0. + JobProtoEnums.INTERNAL_STOP_REASON_CANCELLED; // 0. /** @hide */ public static final int INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED = - JobProtoEnums.STOP_REASON_CONSTRAINTS_NOT_SATISFIED; // 1. + JobProtoEnums.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED; // 1. /** @hide */ public static final int INTERNAL_STOP_REASON_PREEMPT = - JobProtoEnums.STOP_REASON_PREEMPT; // 2. + JobProtoEnums.INTERNAL_STOP_REASON_PREEMPT; // 2. /** * The job ran for at least its minimum execution limit. * @hide */ public static final int INTERNAL_STOP_REASON_TIMEOUT = - JobProtoEnums.STOP_REASON_TIMEOUT; // 3. + JobProtoEnums.INTERNAL_STOP_REASON_TIMEOUT; // 3. /** @hide */ public static final int INTERNAL_STOP_REASON_DEVICE_IDLE = - JobProtoEnums.STOP_REASON_DEVICE_IDLE; // 4. + JobProtoEnums.INTERNAL_STOP_REASON_DEVICE_IDLE; // 4. /** @hide */ public static final int INTERNAL_STOP_REASON_DEVICE_THERMAL = - JobProtoEnums.STOP_REASON_DEVICE_THERMAL; // 5. + JobProtoEnums.INTERNAL_STOP_REASON_DEVICE_THERMAL; // 5. /** * The job is in the {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} * bucket. @@ -71,26 +71,30 @@ public class JobParameters implements Parcelable { * @hide */ public static final int INTERNAL_STOP_REASON_RESTRICTED_BUCKET = - JobProtoEnums.STOP_REASON_RESTRICTED_BUCKET; // 6. + JobProtoEnums.INTERNAL_STOP_REASON_RESTRICTED_BUCKET; // 6. /** * The app was uninstalled. * @hide */ - public static final int INTERNAL_STOP_REASON_UNINSTALL = 7; + public static final int INTERNAL_STOP_REASON_UNINSTALL = + JobProtoEnums.INTERNAL_STOP_REASON_UNINSTALL; // 7. /** * The app's data was cleared. * @hide */ - public static final int INTERNAL_STOP_REASON_DATA_CLEARED = 8; + public static final int INTERNAL_STOP_REASON_DATA_CLEARED = + JobProtoEnums.INTERNAL_STOP_REASON_DATA_CLEARED; // 8. /** * @hide */ - public static final int INTERNAL_STOP_REASON_RTC_UPDATED = 9; + public static final int INTERNAL_STOP_REASON_RTC_UPDATED = + JobProtoEnums.INTERNAL_STOP_REASON_RTC_UPDATED; // 9. /** * The app called jobFinished() on its own. * @hide */ - public static final int INTERNAL_STOP_REASON_SUCCESSFUL_FINISH = 10; + public static final int INTERNAL_STOP_REASON_SUCCESSFUL_FINISH = + JobProtoEnums.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH; // 10. /** * All the stop reason codes. This should be regarded as an immutable array at runtime. @@ -109,6 +113,10 @@ public class JobParameters implements Parcelable { INTERNAL_STOP_REASON_DEVICE_IDLE, INTERNAL_STOP_REASON_DEVICE_THERMAL, INTERNAL_STOP_REASON_RESTRICTED_BUCKET, + INTERNAL_STOP_REASON_UNINSTALL, + INTERNAL_STOP_REASON_DATA_CLEARED, + INTERNAL_STOP_REASON_RTC_UPDATED, + INTERNAL_STOP_REASON_SUCCESSFUL_FINISH, }; /** @@ -363,14 +371,6 @@ public class JobParameters implements Parcelable { } /** - * @deprecated Use {@link #isExpeditedJob()} instead. - */ - @Deprecated - public boolean isForegroundJob() { - return mIsExpedited; - } - - /** * For jobs with {@link android.app.job.JobInfo.Builder#setOverrideDeadline(long)} set, this * provides an easy way to tell whether the job is being executed due to the deadline * expiring. Note: If the job is running because its deadline expired, it implies that its diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java index 3bc7b307c334..9ffef9cdcbde 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java @@ -66,6 +66,23 @@ class Alarm { */ public static final int BATTERY_SAVER_POLICY_INDEX = 3; + /** + * Reason to use for inexact alarms. + */ + static final int EXACT_ALLOW_REASON_NOT_APPLICABLE = -1; + /** + * Caller had SCHEDULE_EXACT_ALARM permission. + */ + static final int EXACT_ALLOW_REASON_PERMISSION = 0; + /** + * Caller was in the power allow-list. + */ + static final int EXACT_ALLOW_REASON_ALLOW_LIST = 1; + /** + * Change wasn't enable for the caller due to compat reasons. + */ + static final int EXACT_ALLOW_REASON_COMPAT = 2; + public final int type; /** * The original trigger time supplied by the caller. This can be in the elapsed or rtc time base @@ -92,13 +109,15 @@ class Alarm { /** The ultimate delivery time to be used for this alarm */ private long mWhenElapsed; private long mMaxWhenElapsed; + public int mExactAllowReason; public AlarmManagerService.PriorityClass priorityClass; /** Broadcast options to use when delivering this alarm */ public Bundle mIdleOptions; Alarm(int type, long when, long requestedWhenElapsed, long windowLength, long interval, PendingIntent op, IAlarmListener rec, String listenerTag, WorkSource ws, int flags, - AlarmManager.AlarmClockInfo info, int uid, String pkgName, Bundle idleOptions) { + AlarmManager.AlarmClockInfo info, int uid, String pkgName, Bundle idleOptions, + int exactAllowReason) { this.type = type; origWhen = when; wakeup = type == AlarmManager.ELAPSED_REALTIME_WAKEUP @@ -119,6 +138,7 @@ class Alarm { this.uid = uid; packageName = pkgName; mIdleOptions = idleOptions; + mExactAllowReason = exactAllowReason; sourcePackage = (operation != null) ? operation.getCreatorPackage() : packageName; creatorUid = (operation != null) ? operation.getCreatorUid() : this.uid; } @@ -216,7 +236,6 @@ class Alarm { sb.append(type); sb.append(" origWhen "); sb.append(origWhen); - sb.append(" "); sb.append(" whenElapsed "); sb.append(getWhenElapsed()); sb.append(" "); @@ -240,6 +259,21 @@ class Alarm { } } + private static String exactReasonToString(int reason) { + switch (reason) { + case EXACT_ALLOW_REASON_ALLOW_LIST: + return "allow-listed"; + case EXACT_ALLOW_REASON_COMPAT: + return "compat"; + case EXACT_ALLOW_REASON_PERMISSION: + return "permission"; + case EXACT_ALLOW_REASON_NOT_APPLICABLE: + return "N/A"; + default: + return "--unknown--"; + } + } + public static String typeToString(int type) { switch (type) { case RTC: @@ -270,6 +304,10 @@ class Alarm { } ipw.print(" window="); TimeUtils.formatDuration(windowLength, ipw); + if (mExactAllowReason != EXACT_ALLOW_REASON_NOT_APPLICABLE) { + ipw.print(" exactAllowReason="); + ipw.print(exactReasonToString(mExactAllowReason)); + } ipw.print(" repeatInterval="); ipw.print(repeatInterval); ipw.print(" count="); 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 e63a7c41ea98..0e362759ef4c 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -38,7 +38,16 @@ import static android.os.UserHandle.USER_SYSTEM; import static com.android.server.alarm.Alarm.APP_STANDBY_POLICY_INDEX; import static com.android.server.alarm.Alarm.BATTERY_SAVER_POLICY_INDEX; import static com.android.server.alarm.Alarm.DEVICE_IDLE_POLICY_INDEX; +import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_ALLOW_LIST; +import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_COMPAT; +import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE; +import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION; import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX; +import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_ALARM_CANCELLED; +import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_DATA_CLEARED; +import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_EXACT_PERMISSION_REVOKED; +import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_PI_CANCELLED; +import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_UNDEFINED; import android.Manifest; import android.annotation.NonNull; @@ -112,6 +121,7 @@ import com.android.internal.app.IAppOpsService; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.LocalLog; +import com.android.internal.util.RingBuffer; import com.android.internal.util.StatLogger; import com.android.server.AlarmManagerInternal; import com.android.server.AppStateTracker; @@ -156,6 +166,7 @@ import java.util.function.Predicate; public class AlarmManagerService extends SystemService { private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP; private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; + private static final int REMOVAL_HISTORY_SIZE_PER_UID = 10; static final int TIME_CHANGED_MASK = 1 << 16; static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK | ELAPSED_REALTIME_WAKEUP_MASK; @@ -194,12 +205,11 @@ public class AlarmManagerService extends SystemService { final LocalLog mLog = new LocalLog(TAG); AppOpsManager mAppOps; - IAppOpsService mAppOpsService; DeviceIdleInternal mLocalDeviceIdleController; private UsageStatsManagerInternal mUsageStatsManagerInternal; private ActivityManagerInternal mActivityManagerInternal; private PackageManagerInternal mPackageManagerInternal; - private PermissionManagerServiceInternal mLocalPermissionManager; + private volatile PermissionManagerServiceInternal mLocalPermissionManager; final Object mLock = new Object(); @@ -223,6 +233,7 @@ public class AlarmManagerService extends SystemService { private final Injector mInjector; int mBroadcastRefCount = 0; + MetricsHelper mMetricsHelper; PowerManager.WakeLock mWakeLock; SparseIntArray mAlarmsPerUid = new SparseIntArray(); ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>(); @@ -233,6 +244,7 @@ public class AlarmManagerService extends SystemService { AppWakeupHistory mAppWakeupHistory; AppWakeupHistory mAllowWhileIdleHistory; private final SparseLongArray mLastPriorityAlarmDispatch = new SparseLongArray(); + private final SparseArray<RingBuffer<RemovedAlarm>> mRemovalHistory = new SparseArray<>(); ClockReceiver mClockReceiver; final DeliveryTracker mDeliveryTracker = new DeliveryTracker(); IBinder.DeathRecipient mListenerDeathRecipient; @@ -387,6 +399,57 @@ public class AlarmManagerService extends SystemService { } } + static class RemovedAlarm { + static final int REMOVE_REASON_UNDEFINED = 0; + static final int REMOVE_REASON_ALARM_CANCELLED = 1; + static final int REMOVE_REASON_EXACT_PERMISSION_REVOKED = 2; + static final int REMOVE_REASON_DATA_CLEARED = 3; + static final int REMOVE_REASON_PI_CANCELLED = 4; + + final String mTag; + final long mWhenRemovedElapsed; + final long mWhenRemovedRtc; + final int mRemoveReason; + + RemovedAlarm(Alarm a, int removeReason, long nowRtc, long nowElapsed) { + mTag = a.statsTag; + mRemoveReason = removeReason; + mWhenRemovedRtc = nowRtc; + mWhenRemovedElapsed = nowElapsed; + } + + static final boolean isLoggable(int reason) { + // We don't want to log meaningless reasons. This also gives a way for callers to + // opt out of logging, e.g. when replacing an alarm. + return reason != REMOVE_REASON_UNDEFINED; + } + + static final String removeReasonToString(int reason) { + switch (reason) { + case REMOVE_REASON_ALARM_CANCELLED: + return "alarm_cancelled"; + case REMOVE_REASON_EXACT_PERMISSION_REVOKED: + return "exact_alarm_permission_revoked"; + case REMOVE_REASON_DATA_CLEARED: + return "data_cleared"; + case REMOVE_REASON_PI_CANCELLED: + return "pi_cancelled"; + default: + return "unknown:" + reason; + } + } + + void dump(IndentingPrintWriter pw, long nowElapsed, SimpleDateFormat sdf) { + pw.print("[tag", mTag); + pw.print("reason", removeReasonToString(mRemoveReason)); + pw.print("elapsed="); + TimeUtils.formatDuration(mWhenRemovedElapsed, nowElapsed, pw); + pw.print(" rtc="); + pw.print(sdf.format(new Date(mWhenRemovedRtc))); + pw.println("]"); + } + } + /** * All times are in milliseconds. These constants are kept synchronized with the system * global Settings. Any access to this class or its fields should be done while @@ -1221,7 +1284,7 @@ public class AlarmManagerService extends SystemService { setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed, nextMaxElapsed - nextElapsed, alarm.repeatInterval, alarm.operation, null, null, alarm.flags, alarm.workSource, alarm.alarmClock, alarm.uid, - alarm.packageName, null); + alarm.packageName, null, EXACT_ALLOW_REASON_NOT_APPLICABLE); // Kernel alarms will be rescheduled as needed in setImplLocked } } @@ -1442,6 +1505,7 @@ public class AlarmManagerService extends SystemService { @Override public void onStart() { mInjector.init(); + mMetricsHelper = new MetricsHelper(getContext(), mLock); mListenerDeathRecipient = new IBinder.DeathRecipient() { @Override @@ -1565,39 +1629,14 @@ public class AlarmManagerService extends SystemService { if (phase == PHASE_SYSTEM_SERVICES_READY) { synchronized (mLock) { mConstants.start(); + mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); - mAppOpsService = mInjector.getAppOpsService(); - try { - mAppOpsService.startWatchingMode(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, null, - new IAppOpsCallback.Stub() { - @Override - public void opChanged(int op, int uid, String packageName) - throws RemoteException { - if (op != AppOpsManager.OP_SCHEDULE_EXACT_ALARM) { - return; - } - if (!hasScheduleExactAlarmInternal(packageName, uid)) { - mHandler.obtainMessage(AlarmHandler.REMOVE_EXACT_ALARMS, - uid, 0, packageName).sendToTarget(); - } - } - }); - } catch (RemoteException e) { - } mLocalDeviceIdleController = LocalServices.getService(DeviceIdleInternal.class); mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class); - mLocalPermissionManager = LocalServices.getService( - PermissionManagerServiceInternal.class); - refreshExactAlarmCandidates(); - - AppStandbyInternal appStandbyInternal = - LocalServices.getService(AppStandbyInternal.class); - appStandbyInternal.addListener(new AppStandbyTracker()); - mAppStateTracker = (AppStateTrackerImpl) LocalServices.getService(AppStateTracker.class); mAppStateTracker.addListener(mForceAppStandbyListener); @@ -1605,6 +1644,34 @@ public class AlarmManagerService extends SystemService { mClockReceiver.scheduleTimeTickEvent(); mClockReceiver.scheduleDateChangedEvent(); } + IAppOpsService iAppOpsService = mInjector.getAppOpsService(); + try { + iAppOpsService.startWatchingMode(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, null, + new IAppOpsCallback.Stub() { + @Override + public void opChanged(int op, int uid, String packageName) + throws RemoteException { + if (op != AppOpsManager.OP_SCHEDULE_EXACT_ALARM) { + return; + } + if (!hasScheduleExactAlarmInternal(packageName, uid)) { + mHandler.obtainMessage(AlarmHandler.REMOVE_EXACT_ALARMS, + uid, 0, packageName).sendToTarget(); + } + } + }); + } catch (RemoteException e) { + } + + mLocalPermissionManager = LocalServices.getService( + PermissionManagerServiceInternal.class); + refreshExactAlarmCandidates(); + + AppStandbyInternal appStandbyInternal = + LocalServices.getService(AppStandbyInternal.class); + appStandbyInternal.addListener(new AppStandbyTracker()); + + mMetricsHelper.registerPuller(() -> mAlarmStore); } } @@ -1684,14 +1751,14 @@ public class AlarmManagerService extends SystemService { void removeImpl(PendingIntent operation, IAlarmListener listener) { synchronized (mLock) { - removeLocked(operation, listener); + removeLocked(operation, listener, REMOVE_REASON_UNDEFINED); } } void setImpl(int type, long triggerAtTime, long windowLength, long interval, PendingIntent operation, IAlarmListener directReceiver, String listenerTag, int flags, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock, - int callingUid, String callingPackage, Bundle idleOptions) { + int callingUid, String callingPackage, Bundle idleOptions, int exactAllowReason) { if ((operation == null && directReceiver == null) || (operation != null && directReceiver != null)) { Slog.w(TAG, "Alarms must either supply a PendingIntent or an AlarmReceiver"); @@ -1788,7 +1855,7 @@ public class AlarmManagerService extends SystemService { } setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, interval, operation, directReceiver, listenerTag, flags, workSource, alarmClock, callingUid, - callingPackage, idleOptions); + callingPackage, idleOptions, exactAllowReason); } } @@ -1796,18 +1863,19 @@ public class AlarmManagerService extends SystemService { long interval, PendingIntent operation, IAlarmListener directReceiver, String listenerTag, int flags, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage, - Bundle idleOptions) { + Bundle idleOptions, int exactAllowReason) { final Alarm a = new Alarm(type, when, whenElapsed, windowLength, interval, operation, directReceiver, listenerTag, workSource, flags, alarmClock, - callingUid, callingPackage, idleOptions); + callingUid, callingPackage, idleOptions, exactAllowReason); if (mActivityManagerInternal.isAppStartModeDisabled(callingUid, callingPackage)) { Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a + " -- package not allowed to start"); return; } - removeLocked(operation, directReceiver); + removeLocked(operation, directReceiver, REMOVE_REASON_UNDEFINED); incrementAlarmCount(a.uid); setImplLocked(a); + MetricsHelper.pushAlarmScheduled(a); } /** @@ -2098,7 +2166,7 @@ public class AlarmManagerService extends SystemService { @Override public void removeAlarmsForUid(int uid) { synchronized (mLock) { - removeLocked(uid); + removeLocked(uid, REMOVE_REASON_DATA_CLEARED); } } @@ -2220,6 +2288,8 @@ public class AlarmManagerService extends SystemService { // Make sure the caller is allowed to use the requested kind of alarm, and also // decide what quota and broadcast options to use. + boolean allowListed = false; // For logging the reason. + boolean changeDisabled = false; // For logging the reason. Bundle idleOptions = null; if ((flags & FLAG_PRIORITIZE) != 0) { getContext().enforcePermission( @@ -2236,6 +2306,7 @@ public class AlarmManagerService extends SystemService { lowerQuota = !exact; idleOptions = exact ? mOptsWithFgs.toBundle() : mOptsWithoutFgs.toBundle(); } else { + changeDisabled = true; needsPermission = false; lowerQuota = allowWhileIdle; idleOptions = allowWhileIdle ? mOptsWithFgs.toBundle() : null; @@ -2250,6 +2321,8 @@ public class AlarmManagerService extends SystemService { } else { Slog.wtf(TAG, errorMessage); } + } else { + allowListed = true; } // If the app is on the full system power allow-list (not except-idle), or we're // in a soft failure mode, we still allow the alarms. @@ -2263,15 +2336,25 @@ public class AlarmManagerService extends SystemService { flags |= FLAG_ALLOW_WHILE_IDLE_COMPAT; } } - - // If this is an exact time alarm, then it can't be batched with other alarms. + final int exactAllowReason; if (exact) { + // If this is an exact time alarm, then it can't be batched with other alarms. flags |= AlarmManager.FLAG_STANDALONE; + + if (changeDisabled) { + exactAllowReason = EXACT_ALLOW_REASON_COMPAT; + } else if (allowListed) { + exactAllowReason = EXACT_ALLOW_REASON_ALLOW_LIST; + } else { + exactAllowReason = EXACT_ALLOW_REASON_PERMISSION; + } + } else { + exactAllowReason = EXACT_ALLOW_REASON_NOT_APPLICABLE; } setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver, listenerTag, flags, workSource, alarmClock, callingUid, callingPackage, - idleOptions); + idleOptions, exactAllowReason); } @Override @@ -2319,7 +2402,7 @@ public class AlarmManagerService extends SystemService { return; } synchronized (mLock) { - removeLocked(operation, listener); + removeLocked(operation, listener, REMOVE_REASON_ALARM_CANCELLED); } } @@ -2665,6 +2748,7 @@ public class AlarmManagerService extends SystemService { pw.println("Allow while idle history:"); mAllowWhileIdleHistory.dump(pw, nowELAPSED); + pw.println(); if (mLastPriorityAlarmDispatch.size() > 0) { pw.println("Last priority alarm dispatches:"); @@ -2679,6 +2763,23 @@ public class AlarmManagerService extends SystemService { pw.decreaseIndent(); } + if (mRemovalHistory.size() > 0) { + pw.println("Removal history: "); + pw.increaseIndent(); + for (int i = 0; i < mRemovalHistory.size(); i++) { + UserHandle.formatUid(pw, mRemovalHistory.keyAt(i)); + pw.println(":"); + pw.increaseIndent(); + final RemovedAlarm[] historyForUid = mRemovalHistory.valueAt(i).toArray(); + for (final RemovedAlarm removedAlarm : historyForUid) { + removedAlarm.dump(pw, nowELAPSED, sdf); + } + pw.decreaseIndent(); + } + pw.decreaseIndent(); + pw.println(); + } + if (mLog.dump(pw, "Recent problems:")) { pw.println(); } @@ -3216,7 +3317,7 @@ public class AlarmManagerService extends SystemService { } return !hasScheduleExactAlarmInternal(a.packageName, a.uid); }; - removeAlarmsInternalLocked(whichAlarms); + removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED); } /** @@ -3224,7 +3325,6 @@ public class AlarmManagerService extends SystemService { * that the app is no longer eligible to use. * * This is not expected to get called frequently. - * TODO (b/179541791): Add revocation history to dumpsys. */ void removeExactAlarmsOnPermissionRevokedLocked(int uid, String packageName) { Slog.w(TAG, "Package " + packageName + ", uid " + uid + " lost SCHEDULE_EXACT_ALARM!"); @@ -3240,26 +3340,22 @@ public class AlarmManagerService extends SystemService { } return false; }; - removeAlarmsInternalLocked(whichAlarms); + removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED); } - private void removeAlarmsInternalLocked(Predicate<Alarm> whichAlarms) { + private void removeAlarmsInternalLocked(Predicate<Alarm> whichAlarms, int reason) { + final long nowRtc = mInjector.getCurrentTimeMillis(); + final long nowElapsed = mInjector.getElapsedRealtime(); + final ArrayList<Alarm> removedAlarms = mAlarmStore.remove(whichAlarms); - final boolean didRemove = !removedAlarms.isEmpty(); - if (didRemove) { - for (final Alarm removed : removedAlarms) { - decrementAlarmCount(removed.uid, 1); - } - } + final boolean removedFromStore = !removedAlarms.isEmpty(); for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) { final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i); for (int j = alarmsForUid.size() - 1; j >= 0; j--) { final Alarm alarm = alarmsForUid.get(j); if (whichAlarms.test(alarm)) { - // Don't set didRemove, since this doesn't impact the scheduled alarms. - alarmsForUid.remove(j); - decrementAlarmCount(alarm.uid, 1); + removedAlarms.add(alarmsForUid.remove(j)); } } if (alarmsForUid.size() == 0) { @@ -3269,13 +3365,24 @@ public class AlarmManagerService extends SystemService { for (int i = mPendingNonWakeupAlarms.size() - 1; i >= 0; i--) { final Alarm a = mPendingNonWakeupAlarms.get(i); if (whichAlarms.test(a)) { - // Don't set didRemove, since this doesn't impact the scheduled alarms. - mPendingNonWakeupAlarms.remove(i); - decrementAlarmCount(a.uid, 1); + removedAlarms.add(mPendingNonWakeupAlarms.remove(i)); } } - if (didRemove) { + for (final Alarm removed : removedAlarms) { + decrementAlarmCount(removed.uid, 1); + if (!RemovedAlarm.isLoggable(reason)) { + continue; + } + RingBuffer<RemovedAlarm> bufferForUid = mRemovalHistory.get(removed.uid); + if (bufferForUid == null) { + bufferForUid = new RingBuffer<>(RemovedAlarm.class, REMOVAL_HISTORY_SIZE_PER_UID); + mRemovalHistory.put(removed.uid, bufferForUid); + } + bufferForUid.append(new RemovedAlarm(removed, reason, nowRtc, nowElapsed)); + } + + if (removedFromStore) { boolean idleUntilUpdated = false; if (mPendingIdleUntil != null && whichAlarms.test(mPendingIdleUntil)) { mPendingIdleUntil = null; @@ -3297,7 +3404,7 @@ public class AlarmManagerService extends SystemService { } } - void removeLocked(PendingIntent operation, IAlarmListener directReceiver) { + void removeLocked(PendingIntent operation, IAlarmListener directReceiver, int reason) { if (operation == null && directReceiver == null) { if (localLOGV) { Slog.w(TAG, "requested remove() of null operation", @@ -3305,15 +3412,15 @@ public class AlarmManagerService extends SystemService { } return; } - removeAlarmsInternalLocked(a -> a.matches(operation, directReceiver)); + removeAlarmsInternalLocked(a -> a.matches(operation, directReceiver), reason); } - void removeLocked(final int uid) { + void removeLocked(final int uid, int reason) { if (uid == Process.SYSTEM_UID) { // If a force-stop occurs for a system-uid package, ignore it. return; } - removeAlarmsInternalLocked(a -> a.uid == uid); + removeAlarmsInternalLocked(a -> a.uid == uid, reason); } void removeLocked(final String packageName) { @@ -3324,7 +3431,7 @@ public class AlarmManagerService extends SystemService { } return; } - removeAlarmsInternalLocked(a -> a.matches(packageName)); + removeAlarmsInternalLocked(a -> a.matches(packageName), REMOVE_REASON_UNDEFINED); } // Only called for ephemeral apps @@ -3335,60 +3442,27 @@ public class AlarmManagerService extends SystemService { } final Predicate<Alarm> whichAlarms = (a) -> (a.uid == uid && mActivityManagerInternal.isAppStartModeDisabled(uid, a.packageName)); - removeAlarmsInternalLocked(whichAlarms); + removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_UNDEFINED); } void removeUserLocked(int userHandle) { if (userHandle == USER_SYSTEM) { - // If we're told we're removing the system user, ignore it. + Slog.w(TAG, "Ignoring attempt to remove system-user state!"); return; } final Predicate<Alarm> whichAlarms = - (Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle; - final ArrayList<Alarm> removedAlarms = mAlarmStore.remove(whichAlarms); - for (final Alarm removed : removedAlarms) { - decrementAlarmCount(removed.uid, 1); - } - final boolean didRemove = !removedAlarms.isEmpty(); + (Alarm a) -> UserHandle.getUserId(a.uid) == userHandle; + removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_UNDEFINED); - for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) { - if (UserHandle.getUserId(mPendingBackgroundAlarms.keyAt(i)) == userHandle) { - final ArrayList<Alarm> toRemove = mPendingBackgroundAlarms.valueAt(i); - if (toRemove != null) { - for (int j = 0; j < toRemove.size(); j++) { - decrementAlarmCount(toRemove.get(j).uid, 1); - } - } - mPendingBackgroundAlarms.removeAt(i); - } - } for (int i = mLastPriorityAlarmDispatch.size() - 1; i >= 0; i--) { if (UserHandle.getUserId(mLastPriorityAlarmDispatch.keyAt(i)) == userHandle) { mLastPriorityAlarmDispatch.removeAt(i); } } - if (mNextWakeFromIdle != null && whichAlarms.test(mNextWakeFromIdle)) { - mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm(); - if (mPendingIdleUntil != null) { - final boolean updated = mAlarmStore.updateAlarmDeliveries(alarm -> { - if (alarm != mPendingIdleUntil) { - return false; - } - return adjustIdleUntilTime(alarm); - }); - if (updated) { - mAlarmStore.updateAlarmDeliveries( - alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm)); - } - } - } - - if (didRemove) { - if (DEBUG_BATCH) { - Slog.v(TAG, "remove(user) changed bounds; rebatching"); + for (int i = mRemovalHistory.size() - 1; i >= 0; i--) { + if (UserHandle.getUserId(mRemovalHistory.keyAt(i)) == userHandle) { + mRemovalHistory.removeAt(i); } - rescheduleKernelAlarmsLocked(); - updateNextAlarmClockLocked(); } } @@ -3501,8 +3575,8 @@ public class AlarmManagerService extends SystemService { private static native int setKernelTimezone(long nativeData, int minuteswest); private static native long getNextAlarm(long nativeData, int type); - boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) { - boolean hasWakeup = false; + int triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) { + int wakeUps = 0; final ArrayList<Alarm> pendingAlarms = mAlarmStore.removePendingAlarms(nowELAPSED); for (final Alarm alarm : pendingAlarms) { if (isBackgroundRestricted(alarm)) { @@ -3559,11 +3633,11 @@ public class AlarmManagerService extends SystemService { setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed, nextMaxElapsed - nextElapsed, alarm.repeatInterval, alarm.operation, null, null, alarm.flags, alarm.workSource, alarm.alarmClock, alarm.uid, - alarm.packageName, null); + alarm.packageName, null, EXACT_ALLOW_REASON_NOT_APPLICABLE); } if (alarm.wakeup) { - hasWakeup = true; + wakeUps++; } // We removed an alarm clock. Let the caller recompute the next alarm clock. @@ -3584,7 +3658,7 @@ public class AlarmManagerService extends SystemService { } } - return hasWakeup; + return wakeUps; } long currentNonWakeupFuzzLocked(long nowELAPSED) { @@ -3843,8 +3917,8 @@ public class AlarmManagerService extends SystemService { } mLastTrigger = nowELAPSED; - boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED); - if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) { + final int wakeUps = triggerAlarmsLocked(triggerList, nowELAPSED); + if (wakeUps == 0 && checkAllowNonWakeupDelayLocked(nowELAPSED)) { // if there are no wakeup alarms and the screen is off, we can // delay what we have so far until the future. if (mPendingNonWakeupAlarms.size() == 0) { @@ -3896,6 +3970,7 @@ public class AlarmManagerService extends SystemService { reorderAlarmsBasedOnStandbyBuckets(triggerPackages); rescheduleKernelAlarmsLocked(); updateNextAlarmClockLocked(); + MetricsHelper.pushAlarmBatchDelivered(triggerList.size(), wakeUps); } } @@ -4032,7 +4107,7 @@ public class AlarmManagerService extends SystemService { case REMOVE_FOR_CANCELED: final PendingIntent operation = (PendingIntent) msg.obj; synchronized (mLock) { - removeLocked(operation, null); + removeLocked(operation, null, REMOVE_REASON_PI_CANCELLED); } break; @@ -4126,7 +4201,7 @@ public class AlarmManagerService extends SystemService { setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtime() + tickEventDelay, 0, 0, null, mTimeTickTrigger, TIME_TICK_TAG, flags, workSource, null, - Process.myUid(), "android", null); + Process.myUid(), "android", null, EXACT_ALLOW_REASON_ALLOW_LIST); // Finally, remember when we set the tick alarm synchronized (mLock) { @@ -4146,7 +4221,7 @@ public class AlarmManagerService extends SystemService { final WorkSource workSource = null; // Let system take blame for date change events. setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, null, null, AlarmManager.FLAG_STANDALONE, workSource, null, - Process.myUid(), "android", null); + Process.myUid(), "android", null, EXACT_ALLOW_REASON_ALLOW_LIST); } } @@ -4212,6 +4287,7 @@ public class AlarmManagerService extends SystemService { return; case Intent.ACTION_UID_REMOVED: mLastPriorityAlarmDispatch.delete(uid); + mRemovalHistory.delete(uid); return; case Intent.ACTION_PACKAGE_REMOVED: if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { @@ -4241,7 +4317,7 @@ public class AlarmManagerService extends SystemService { // package-removed and package-restarted case mAppWakeupHistory.removeForPackage(pkg, UserHandle.getUserId(uid)); mAllowWhileIdleHistory.removeForPackage(pkg, UserHandle.getUserId(uid)); - removeLocked(uid); + removeLocked(uid, REMOVE_REASON_UNDEFINED); } else { // external-applications-unavailable case removeLocked(pkg); diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java index e684b84748b1..0172748a95fa 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java @@ -139,6 +139,11 @@ public interface AlarmStore { String getName(); /** + * Returns the number of alarms that satisfy the given condition. + */ + int getCount(Predicate<Alarm> condition); + + /** * A functional interface used to update the alarm. Used to describe the update in * {@link #updateAlarmDeliveries(AlarmDeliveryCalculator)} */ @@ -153,4 +158,3 @@ public interface AlarmStore { boolean updateAlarmDelivery(Alarm a); } } - diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java index cb528ba2769a..1a4efb8ffcd9 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java @@ -17,7 +17,6 @@ package com.android.server.alarm; import static com.android.server.alarm.AlarmManagerService.DEBUG_BATCH; -import static com.android.server.alarm.AlarmManagerService.TAG; import static com.android.server.alarm.AlarmManagerService.clampPositive; import static com.android.server.alarm.AlarmManagerService.dumpAlarmList; import static com.android.server.alarm.AlarmManagerService.isTimeTickAlarm; @@ -50,10 +49,12 @@ public class BatchingAlarmStore implements AlarmStore { interface Stats { int REBATCH_ALL_ALARMS = 0; + int GET_COUNT = 1; } final StatLogger mStatLogger = new StatLogger(TAG + " stats", new String[]{ "REBATCH_ALL_ALARMS", + "GET_COUNT", }); private static final Comparator<Batch> sBatchOrder = Comparator.comparingLong(b -> b.mStart); @@ -219,6 +220,22 @@ public class BatchingAlarmStore implements AlarmStore { return TAG; } + @Override + public int getCount(Predicate<Alarm> condition) { + long start = mStatLogger.getTime(); + + int count = 0; + for (Batch b : mAlarmBatches) { + for (int i = 0; i < b.size(); i++) { + if (condition.test(b.get(i))) { + count++; + } + } + } + mStatLogger.logDurationStat(Stats.GET_COUNT, start); + return count; + } + private void insertAndBatchAlarm(Alarm alarm) { final int whichBatch = ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) ? -1 : attemptCoalesce(alarm.getWhenElapsed(), alarm.getMaxWhenElapsed()); diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java index 9b1b06658a98..2e12e2f34ea0 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java @@ -47,11 +47,13 @@ public class LazyAlarmStore implements AlarmStore { interface Stats { int GET_NEXT_DELIVERY_TIME = 0; int GET_NEXT_WAKEUP_DELIVERY_TIME = 1; + int GET_COUNT = 2; } final StatLogger mStatLogger = new StatLogger(TAG + " stats", new String[]{ "GET_NEXT_DELIVERY_TIME", "GET_NEXT_WAKEUP_DELIVERY_TIME", + "GET_COUNT", }); // Decreasing time order because it is more efficient to remove from the tail of an array list. @@ -221,4 +223,18 @@ public class LazyAlarmStore implements AlarmStore { public String getName() { return TAG; } + + @Override + public int getCount(Predicate<Alarm> condition) { + long start = mStatLogger.getTime(); + + int count = 0; + for (final Alarm a : mAlarms) { + if (condition.test(a)) { + count++; + } + } + mStatLogger.logDurationStat(Stats.GET_COUNT, start); + return count; + } } diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java new file mode 100644 index 000000000000..2dc131c0bda9 --- /dev/null +++ b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java @@ -0,0 +1,113 @@ +/* + * 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.alarm; + +import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST; +import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED; +import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__NOT_APPLICABLE; +import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION; +import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY; + +import android.app.AlarmManager; +import android.app.StatsManager; +import android.content.Context; +import android.os.SystemClock; + +import com.android.internal.os.BackgroundThread; +import com.android.internal.util.FrameworkStatsLog; + +import java.util.function.Supplier; + +/** + * A helper class to write logs to statsd. + */ +class MetricsHelper { + private final Context mContext; + private final Object mLock; + + MetricsHelper(Context context, Object lock) { + mContext = context; + mLock = lock; + } + + void registerPuller(Supplier<AlarmStore> alarmStoreSupplier) { + final StatsManager statsManager = mContext.getSystemService(StatsManager.class); + statsManager.setPullAtomCallback(FrameworkStatsLog.PENDING_ALARM_INFO, null, + BackgroundThread.getExecutor(), (atomTag, data) -> { + if (atomTag != FrameworkStatsLog.PENDING_ALARM_INFO) { + throw new UnsupportedOperationException("Unknown tag" + atomTag); + } + final long now = SystemClock.elapsedRealtime(); + synchronized (mLock) { + final AlarmStore alarmStore = alarmStoreSupplier.get(); + data.add(FrameworkStatsLog.buildStatsEvent(atomTag, + alarmStore.size(), + alarmStore.getCount(a -> a.windowLength == 0), + alarmStore.getCount(a -> a.wakeup), + alarmStore.getCount( + a -> (a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0), + alarmStore.getCount( + a -> (a.flags & AlarmManager.FLAG_PRIORITIZE) != 0), + alarmStore.getCount(a -> (a.operation != null + && a.operation.isForegroundService())), + alarmStore.getCount( + a -> (a.operation != null && a.operation.isActivity())), + alarmStore.getCount( + a -> (a.operation != null && a.operation.isService())), + alarmStore.getCount(a -> (a.listener != null)), + alarmStore.getCount( + a -> (a.getRequestedElapsed() > now + INDEFINITE_DELAY)), + alarmStore.getCount(a -> (a.repeatInterval != 0)), + alarmStore.getCount(a -> (a.alarmClock != null)) + )); + return StatsManager.PULL_SUCCESS; + } + }); + } + + private static int reasonToStatsReason(int reasonCode) { + switch (reasonCode) { + case Alarm.EXACT_ALLOW_REASON_ALLOW_LIST: + return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST; + case Alarm.EXACT_ALLOW_REASON_PERMISSION: + return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION; + case Alarm.EXACT_ALLOW_REASON_COMPAT: + return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED; + default: + return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__NOT_APPLICABLE; + } + } + + static void pushAlarmScheduled(Alarm a) { + FrameworkStatsLog.write( + FrameworkStatsLog.ALARM_SCHEDULED, + a.uid, + a.windowLength == 0, + a.wakeup, + (a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0, + a.alarmClock != null, + a.repeatInterval != 0, + reasonToStatsReason(a.mExactAllowReason)); + } + + static void pushAlarmBatchDelivered(int numAlarms, int wakeups) { + FrameworkStatsLog.write( + FrameworkStatsLog.ALARM_BATCH_DELIVERED, + numAlarms, + wakeups); + } +} 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 313cd208f7fb..452be3008a32 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -1088,7 +1088,7 @@ public class JobSchedulerService extends com.android.server.SystemService FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED, uId, null, jobStatus.getBatteryName(), FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED, - JobProtoEnums.STOP_REASON_UNKNOWN, jobStatus.getStandbyBucket(), + JobProtoEnums.INTERNAL_STOP_REASON_UNKNOWN, jobStatus.getStandbyBucket(), jobStatus.getJobId(), jobStatus.hasChargingConstraint(), jobStatus.hasBatteryNotLowConstraint(), @@ -1099,7 +1099,8 @@ public class JobSchedulerService extends com.android.server.SystemService jobStatus.hasConnectivityConstraint(), jobStatus.hasContentTriggerConstraint(), jobStatus.isRequestedExpeditedJob(), - /* isRunningAsExpeditedJob */ false); + /* isRunningAsExpeditedJob */ false, + JobProtoEnums.STOP_REASON_UNDEFINED); // If the job is immediately ready to run, then we can just immediately // put it in the pending list and try to schedule it. This is especially diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java index 6ab2be32f5c3..3fa1c12ce762 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -314,7 +314,8 @@ public final class JobServiceContext implements ServiceConnection { FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED, job.getSourceUid(), null, job.getBatteryName(), FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__STARTED, - JobProtoEnums.STOP_REASON_UNKNOWN, job.getStandbyBucket(), job.getJobId(), + JobProtoEnums.INTERNAL_STOP_REASON_UNKNOWN, + job.getStandbyBucket(), job.getJobId(), job.hasChargingConstraint(), job.hasBatteryNotLowConstraint(), job.hasStorageNotLowConstraint(), @@ -324,7 +325,8 @@ public final class JobServiceContext implements ServiceConnection { job.hasConnectivityConstraint(), job.hasContentTriggerConstraint(), job.isRequestedExpeditedJob(), - job.shouldTreatAsExpeditedJob()); + job.shouldTreatAsExpeditedJob(), + JobProtoEnums.STOP_REASON_UNDEFINED); try { mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid()); } catch (RemoteException e) { @@ -923,7 +925,8 @@ public final class JobServiceContext implements ServiceConnection { completedJob.hasConnectivityConstraint(), completedJob.hasContentTriggerConstraint(), completedJob.isRequestedExpeditedJob(), - completedJob.startedAsExpeditedJob); + completedJob.startedAsExpeditedJob, + mParams.getStopReason()); try { mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), mRunningJob.getSourceUid(), internalStopReason); diff --git a/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl b/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl index 3d5321c9d7d8..e347ebf4a983 100644 --- a/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl +++ b/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl @@ -19,7 +19,7 @@ import android.media.Session2Token; import android.media.MediaParceledListSlice; /** {@hide} */ -interface IMediaCommunicationServiceCallback { +oneway interface IMediaCommunicationServiceCallback { void onSession2Created(in Session2Token token); void onSession2Changed(in MediaParceledListSlice tokens); } diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp index 7020f1824fda..1bf732ba33f2 100644 --- a/apex/media/framework/Android.bp +++ b/apex/media/framework/Android.bp @@ -41,7 +41,10 @@ java_library { installable: true, sdk_version: "module_current", - libs: ["framework-annotations-lib"], + libs: [ + "androidx.annotation_annotation", + "framework-annotations-lib", + ], static_libs: [ "exoplayer2-extractor", "mediatranscoding_aidl_interface-java", diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index cff422d0aafe..8cc3bc08dfb5 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -28,6 +28,10 @@ import android.util.Log; import android.util.Pair; import android.util.SparseArray; +import androidx.annotation.RequiresApi; + +import com.android.modules.utils.build.SdkLevel; + import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.ParserException; @@ -1068,7 +1072,7 @@ public final class MediaParser { private boolean mReleased; // MediaMetrics fields. - @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE; + @Nullable private LogSessionId mLogSessionId; private final boolean mCreatedByName; private final SparseArray<Format> mTrackFormats; private String mLastObservedExceptionName; @@ -1331,7 +1335,7 @@ public final class MediaParser { MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH)); nativeSubmitMetrics( - // TODO: mLogSessionId, + SdkLevel.isAtLeastS() ? getLogSessionIdStringV31() : "", mParserName, mCreatedByName, String.join(MEDIAMETRICS_ELEMENT_SEPARATOR, mParserNamesPool), @@ -1345,13 +1349,15 @@ public final class MediaParser { videoHeight); } - public void setLogSessionId(@NonNull LogSessionId sessionId) { - this.mLogSessionId = Objects.requireNonNull(sessionId); + @RequiresApi(31) + public void setLogSessionId(@NonNull LogSessionId logSessionId) { + this.mLogSessionId = Objects.requireNonNull(logSessionId); } + @RequiresApi(31) @NonNull public LogSessionId getLogSessionId() { - return mLogSessionId; + return mLogSessionId != null ? mLogSessionId : LogSessionId.LOG_SESSION_ID_NONE; } // Private methods. @@ -1548,6 +1554,11 @@ public final class MediaParser { return (String) mParserParameters.getOrDefault(name, defaultValue); } + @RequiresApi(31) + private String getLogSessionIdStringV31() { + return mLogSessionId != null ? mLogSessionId.getStringId() : ""; + } + // Private classes. private static final class InputReadingDataReader implements DataReader { @@ -2197,7 +2208,7 @@ public final class MediaParser { // Native methods. private native void nativeSubmitMetrics( - // TODO: String logSessionId, + String logSessionId, String parserName, boolean createdByName, String parserPool, diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java index d7e960942eae..d1106a2b79c3 100644 --- a/apex/media/framework/java/android/media/MediaTranscodeManager.java +++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java @@ -22,6 +22,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.app.ActivityManager; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; @@ -36,6 +37,7 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.annotation.MinSdk; +import com.android.modules.utils.build.SdkLevel; import java.io.FileNotFoundException; import java.lang.annotation.Retention; @@ -119,6 +121,7 @@ public final class MediaTranscodeManager { private final String mPackageName; private final int mPid; private final int mUid; + private final boolean mIsLowRamDevice; private final ExecutorService mExecutor = Executors.newSingleThreadExecutor(); private final HashMap<Integer, TranscodingSession> mPendingTranscodingSessions = new HashMap(); private final Object mLock = new Object(); @@ -199,7 +202,16 @@ public final class MediaTranscodeManager { } } - private static IMediaTranscodingService getService(boolean retry) { + private IMediaTranscodingService getService(boolean retry) { + // Do not try to get the service on pre-S. The service is lazy-start and getting the + // service could block. + if (!SdkLevel.isAtLeastS()) { + return null; + } + // Do not try to get the service on AndroidGo (low-ram) devices. + if (mIsLowRamDevice) { + return null; + } int retryCount = !retry ? 1 : CONNECT_SERVICE_RETRY_COUNT; Log.i(TAG, "get service with retry " + retryCount); for (int count = 1; count <= retryCount; count++) { @@ -417,6 +429,7 @@ public final class MediaTranscodeManager { mPackageName = mContext.getPackageName(); mUid = Os.getuid(); mPid = Os.getpid(); + mIsLowRamDevice = mContext.getSystemService(ActivityManager.class).isLowRamDevice(); IMediaTranscodingService service = getService(false /*retry*/); if (service != null) { mTranscodingClient = registerClient(service); diff --git a/apex/media/framework/jni/android_media_MediaParserJNI.cpp b/apex/media/framework/jni/android_media_MediaParserJNI.cpp index 7fc4628984f5..c81152c0954c 100644 --- a/apex/media/framework/jni/android_media_MediaParserJNI.cpp +++ b/apex/media/framework/jni/android_media_MediaParserJNI.cpp @@ -29,6 +29,7 @@ namespace { constexpr char kMediaMetricsKey[] = "mediaparser"; +constexpr char kAttributeLogSessionId[] = "android.media.mediaparser.logSessionId"; constexpr char kAttributeParserName[] = "android.media.mediaparser.parserName"; constexpr char kAttributeCreatedByName[] = "android.media.mediaparser.createdByName"; constexpr char kAttributeParserPool[] = "android.media.mediaparser.parserPool"; @@ -65,11 +66,14 @@ public: } // namespace -JNI_FUNCTION(void, nativeSubmitMetrics, jstring parserNameJstring, jboolean createdByName, - jstring parserPoolJstring, jstring lastExceptionJstring, jlong resourceByteCount, - jlong durationMillis, jstring trackMimeTypesJstring, jstring trackCodecsJstring, - jstring alteredParameters, jint videoWidth, jint videoHeight) { +JNI_FUNCTION(void, nativeSubmitMetrics, jstring logSessionIdJstring, jstring parserNameJstring, + jboolean createdByName, jstring parserPoolJstring, jstring lastExceptionJstring, + jlong resourceByteCount, jlong durationMillis, jstring trackMimeTypesJstring, + jstring trackCodecsJstring, jstring alteredParameters, jint videoWidth, + jint videoHeight) { mediametrics_handle_t item(mediametrics_create(kMediaMetricsKey)); + mediametrics_setCString(item, kAttributeLogSessionId, + JstringHandle(env, logSessionIdJstring).value()); mediametrics_setCString(item, kAttributeParserName, JstringHandle(env, parserNameJstring).value()); mediametrics_setInt32(item, kAttributeCreatedByName, createdByName ? 1 : 0); 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 06de3f8d27d0..ed31aa3d2a39 100644 --- a/apex/media/service/java/com/android/server/media/MediaCommunicationService.java +++ b/apex/media/service/java/com/android/server/media/MediaCommunicationService.java @@ -65,17 +65,17 @@ public class MediaCommunicationService extends SystemService { final Context mContext; - private final Object mLock = new Object(); - private final Handler mHandler = new Handler(Looper.getMainLooper()); + final Object mLock = new Object(); + 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(); + final Executor mRecordExecutor = Executors.newSingleThreadExecutor(); @GuardedBy("mLock") - private final List<CallbackRecord> mCallbackRecords = new ArrayList<>(); + final List<CallbackRecord> mCallbackRecords = new ArrayList<>(); final NotificationManager mNotificationManager; public MediaCommunicationService(Context context) { @@ -111,14 +111,14 @@ public class MediaCommunicationService extends SystemService { FullUserRecord user = getFullUserRecordLocked(userId); if (user != null) { if (user.getFullUserId() == userId) { - user.destroySessionsForUserLocked(UserHandle.ALL.getIdentifier()); + user.destroyAllSessions(); mUserRecords.remove(userId); } else { - user.destroySessionsForUserLocked(userId); + user.destroySessionsForUser(userId); } } - updateUser(); } + updateUser(); } @Nullable @@ -134,6 +134,22 @@ public class MediaCommunicationService extends SystemService { return null; } + List<Session2Token> getSession2TokensLocked(int userId) { + List<Session2Token> list = new ArrayList<>(); + if (userId == ALL.getIdentifier()) { + int size = mUserRecords.size(); + for (int i = 0; i < size; i++) { + list.addAll(mUserRecords.valueAt(i).getAllSession2Tokens()); + } + } else { + FullUserRecord user = getFullUserRecordLocked(userId); + if (user != null) { + list.addAll(user.getSession2Tokens(userId)); + } + } + return list; + } + private FullUserRecord getFullUserRecordLocked(int userId) { int fullUserId = mFullUserIds.get(userId, -1); if (fullUserId < 0) { @@ -188,27 +204,54 @@ public class MediaCommunicationService extends SystemService { } } - 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 dispatchSession2Created(Session2Token token) { + synchronized (mLock) { + for (CallbackRecord record : mCallbackRecords) { + if (record.mUserId != ALL.getIdentifier() + && record.mUserId != getUserHandleForUid(token.getUid()).getIdentifier()) { + continue; + } + try { + record.mCallback.onSession2Created(token); + } catch (RemoteException e) { + Log.w(TAG, "Failed to notify session2 token created " + record); + } } } } - void onSessionDied(Session2Record record) { + void dispatchSession2Changed(int userId) { + MediaParceledListSlice<Session2Token> allSession2Tokens; + MediaParceledListSlice<Session2Token> userSession2Tokens; + synchronized (mLock) { - destroySessionLocked(record); + allSession2Tokens = + new MediaParceledListSlice<>(getSession2TokensLocked(ALL.getIdentifier())); + userSession2Tokens = new MediaParceledListSlice<>(getSession2TokensLocked(userId)); + } + allSession2Tokens.setInlineCountLimit(1); + userSession2Tokens.setInlineCountLimit(1); + + synchronized (mLock) { + for (CallbackRecord record : mCallbackRecords) { + if (record.mUserId == ALL.getIdentifier()) { + try { + record.mCallback.onSession2Changed(allSession2Tokens); + } catch (RemoteException e) { + Log.w(TAG, "Failed to notify session2 tokens changed " + record); + } + } else if (record.mUserId == userId) { + try { + record.mCallback.onSession2Changed(userSession2Tokens); + } catch (RemoteException e) { + Log.w(TAG, "Failed to notify session2 tokens changed " + record); + } + } + } } } - private void destroySessionLocked(Session2Record session) { + void onSessionDied(Session2Record session) { if (DEBUG) { Log.d(TAG, "Destroying " + session); } @@ -217,12 +260,10 @@ public class MediaCommunicationService extends SystemService { return; } - FullUserRecord user = getFullUserRecordLocked(session.getUserId()); - + FullUserRecord user = session.getFullUser(); if (user != null) { user.removeSession(session); } - session.close(); } @@ -241,17 +282,17 @@ public class MediaCommunicationService extends SystemService { throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid + " but actually=" + sessionToken.getUid()); } + FullUserRecord user; + int userId = getUserHandleForUid(sessionToken.getUid()).getIdentifier(); 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)); + user = getFullUserRecordLocked(userId); + } + if (user == null) { + Log.w(TAG, "notifySession2Created: Ignore session of an unknown user"); + return; } + user.addSession(new Session2Record(MediaCommunicationService.this, + user, sessionToken, mRecordExecutor)); } finally { Binder.restoreCallingIdentity(token); } @@ -299,10 +340,11 @@ public class MediaCommunicationService extends SystemService { int resolvedUserId = handleIncomingUser(pid, uid, userId, null); List<Session2Token> result; synchronized (mLock) { - FullUserRecord user = getFullUserRecordLocked(userId); - result = user.getSession2Tokens(resolvedUserId); + result = getSession2TokensLocked(resolvedUserId); } - return new MediaParceledListSlice(result); + MediaParceledListSlice parceledListSlice = new MediaParceledListSlice<>(result); + parceledListSlice.setInlineCountLimit(1); + return parceledListSlice; } finally { Binder.restoreCallingIdentity(token); } @@ -427,7 +469,8 @@ public class MediaCommunicationService extends SystemService { final class FullUserRecord { private final int mFullUserId; - /** Sorted list of media sessions */ + private final Object mUserLock = new Object(); + @GuardedBy("mUserLock") private final List<Session2Record> mSessionRecords = new ArrayList<>(); FullUserRecord(int fullUserId) { @@ -435,11 +478,18 @@ public class MediaCommunicationService extends SystemService { } public void addSession(Session2Record record) { - mSessionRecords.add(record); + synchronized (mUserLock) { + mSessionRecords.add(record); + } + mHandler.post(() -> dispatchSession2Created(record.mSessionToken)); + mHandler.post(() -> dispatchSession2Changed(mFullUserId)); } - public void removeSession(Session2Record record) { - mSessionRecords.remove(record); + private void removeSession(Session2Record record) { + synchronized (mUserLock) { + mSessionRecords.remove(record); + } + mHandler.post(() -> dispatchSession2Changed(mFullUserId)); //TODO: Handle if the removed session was the media button session. } @@ -447,42 +497,68 @@ public class MediaCommunicationService extends SystemService { return mFullUserId; } + public List<Session2Token> getAllSession2Tokens() { + synchronized (mUserLock) { + return mSessionRecords.stream() + .map(Session2Record::getSessionToken) + .collect(Collectors.toList()); + } + } + 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()); + synchronized (mUserLock) { + return mSessionRecords.stream() + .filter(record -> 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); + public void destroyAllSessions() { + synchronized (mUserLock) { + for (Session2Record session : mSessionRecords) { + session.close(); + } + mSessionRecords.clear(); + } + mHandler.post(() -> dispatchSession2Changed(mFullUserId)); + } + + public void destroySessionsForUser(int userId) { + boolean changed = false; + synchronized (mUserLock) { + for (int i = mSessionRecords.size() - 1; i >= 0; i--) { + Session2Record session = mSessionRecords.get(i); + if (session.getUserId() == userId) { + mSessionRecords.remove(i); + session.close(); + changed = true; } } } + if (changed) { + mHandler.post(() -> dispatchSession2Changed(mFullUserId)); + } } } static final class Session2Record { - private final Session2Token mSessionToken; - private final Object mLock = new Object(); - private final WeakReference<MediaCommunicationService> mServiceRef; - @GuardedBy("mLock") + final Session2Token mSessionToken; + final Object mSession2RecordLock = new Object(); + final WeakReference<MediaCommunicationService> mServiceRef; + final WeakReference<FullUserRecord> mFullUserRef; + @GuardedBy("mSession2RecordLock") private final MediaController2 mController; - @GuardedBy("mLock") - private boolean mIsConnected; - @GuardedBy("mLock") + @GuardedBy("mSession2RecordLock") + boolean mIsConnected; + @GuardedBy("mSession2RecordLock") private boolean mIsClosed; - Session2Record(MediaCommunicationService service, Session2Token token, - Executor controllerExecutor) { + Session2Record(MediaCommunicationService service, FullUserRecord fullUser, + Session2Token token, Executor controllerExecutor) { mServiceRef = new WeakReference<>(service); + mFullUserRef = new WeakReference<>(fullUser); mSessionToken = token; mController = new MediaController2.Builder(service.getContext(), token) .setControllerCallback(controllerExecutor, new Controller2Callback()) @@ -493,23 +569,19 @@ public class MediaCommunicationService extends SystemService { return UserHandle.getUserHandleForUid(mSessionToken.getUid()).getIdentifier(); } - public boolean isActive() { - synchronized (mLock) { - return mIsConnected; - } + public FullUserRecord getFullUser() { + return mFullUserRef.get(); } public boolean isClosed() { - synchronized (mLock) { + synchronized (mSession2RecordLock) { return mIsClosed; } } public void close() { - synchronized (mLock) { + synchronized (mSession2RecordLock) { mIsClosed = true; - // Call close regardless of the mIsConnected. This may be called when it's not yet - // connected. mController.close(); } } @@ -525,13 +597,9 @@ public class MediaCommunicationService extends SystemService { if (DEBUG) { Log.d(TAG, "connected to " + mSessionToken + ", allowed=" + allowedCommands); } - synchronized (mLock) { + synchronized (mSession2RecordLock) { mIsConnected = true; } - MediaCommunicationService service = mServiceRef.get(); - if (service != null) { - //TODO: notify session state changed - } } @Override @@ -539,7 +607,7 @@ public class MediaCommunicationService extends SystemService { if (DEBUG) { Log.d(TAG, "disconnected from " + mSessionToken); } - synchronized (mLock) { + synchronized (mSession2RecordLock) { mIsConnected = false; } MediaCommunicationService service = mServiceRef.get(); diff --git a/api/Android.bp b/api/Android.bp index 65712704f358..5b733883063a 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -370,7 +370,7 @@ genrule { { targets: ["sdk", "win_sdk"], dir: "apistubs/android/system-server/api", - dest: "merge-android.txt", + dest: "android.txt", }, ], } @@ -394,7 +394,7 @@ genrule { { targets: ["sdk", "win_sdk"], dir: "apistubs/android/system-server/api", - dest: "merge-removed.txt", + dest: "removed.txt", }, ], } diff --git a/cmds/bootanimation/BootAnimationUtil.cpp b/cmds/bootanimation/BootAnimationUtil.cpp index 1e417e938359..4f56e5a88c4c 100644 --- a/cmds/bootanimation/BootAnimationUtil.cpp +++ b/cmds/bootanimation/BootAnimationUtil.cpp @@ -49,7 +49,14 @@ bool bootAnimationDisabled() { } property_get("ro.boot.quiescent", value, "0"); - return atoi(value) > 0; + if (atoi(value) > 0) { + // Only show the bootanimation for quiescent boots if this system property is set to enabled + if (!property_get_bool("ro.bootanim.quiescent.enabled", false)) { + return true; + } + } + + return false; } void waitForSurfaceFlinger() { diff --git a/cmds/dpm/Android.bp b/cmds/dpm/Android.bp index 665abcd7314d..6819d0982d2c 100644 --- a/cmds/dpm/Android.bp +++ b/cmds/dpm/Android.bp @@ -18,8 +18,7 @@ license { ], } -java_binary { +sh_binary { name: "dpm", - wrapper: "dpm", - srcs: ["**/*.java"], + src: "dpm", } diff --git a/cmds/dpm/dpm b/cmds/dpm/dpm index e0efdc15a706..784db5b352a9 100755 --- a/cmds/dpm/dpm +++ b/cmds/dpm/dpm @@ -1,7 +1,5 @@ #!/system/bin/sh # Script to start "dpm" on the device # -base=/system -export CLASSPATH=$base/framework/dpm.jar -exec app_process $base/bin com.android.commands.dpm.Dpm "$@" +cmd device_policy "$@" diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java deleted file mode 100644 index d0c2a24d5314..000000000000 --- a/cmds/dpm/src/com/android/commands/dpm/Dpm.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2014 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.commands.dpm; - -import android.app.ActivityManager; -import android.app.IActivityManager; -import android.app.admin.DevicePolicyManager; -import android.app.admin.IDevicePolicyManager; -import android.content.ComponentName; -import android.content.Context; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.UserHandle; - -import com.android.internal.os.BaseCommand; - -import java.io.PrintStream; - -public final class Dpm extends BaseCommand { - - /** - * Command-line entry point. - * - * @param args The command-line arguments - */ - public static void main(String[] args) { - (new Dpm()).run(args); - } - - private static final String COMMAND_SET_ACTIVE_ADMIN = "set-active-admin"; - private static final String COMMAND_SET_DEVICE_OWNER = "set-device-owner"; - private static final String COMMAND_SET_PROFILE_OWNER = "set-profile-owner"; - private static final String COMMAND_REMOVE_ACTIVE_ADMIN = "remove-active-admin"; - private static final String COMMAND_CLEAR_FREEZE_PERIOD_RECORD = "clear-freeze-period-record"; - private static final String COMMAND_FORCE_NETWORK_LOGS = "force-network-logs"; - private static final String COMMAND_FORCE_SECURITY_LOGS = "force-security-logs"; - private static final String COMMAND_MARK_PO_ON_ORG_OWNED_DEVICE = - "mark-profile-owner-on-organization-owned-device"; - - private IDevicePolicyManager mDevicePolicyManager; - private int mUserId = UserHandle.USER_SYSTEM; - private String mName = ""; - private ComponentName mComponent = null; - - @Override - public void onShowUsage(PrintStream out) { - out.println( - "usage: dpm [subcommand] [options]\n" + - "usage: dpm set-active-admin [ --user <USER_ID> | current ] <COMPONENT>\n" + - // STOPSHIP Finalize it - "usage: dpm set-device-owner [ --user <USER_ID> | current *EXPERIMENTAL* ] " + - "[ --name <NAME> ] <COMPONENT>\n" + - "usage: dpm set-profile-owner [ --user <USER_ID> | current ] [ --name <NAME> ] " + - "<COMPONENT>\n" + - "usage: dpm remove-active-admin [ --user <USER_ID> | current ] [ --name <NAME> ] " + - "<COMPONENT>\n" + - "\n" + - "dpm set-active-admin: Sets the given component as active admin" + - " for an existing user.\n" + - "\n" + - "dpm set-device-owner: Sets the given component as active admin, and its" + - " package as device owner.\n" + - "\n" + - "dpm set-profile-owner: Sets the given component as active admin and profile" + - " owner for an existing user.\n" + - "\n" + - "dpm remove-active-admin: Disables an active admin, the admin must have declared" + - " android:testOnly in the application in its manifest. This will also remove" + - " device and profile owners.\n" + - "\n" + - "dpm " + COMMAND_CLEAR_FREEZE_PERIOD_RECORD + ": clears framework-maintained " + - "record of past freeze periods that the device went through. For use during " + - "feature development to prevent triggering restriction on setting freeze " + - "periods.\n" + - "\n" + - "dpm " + COMMAND_FORCE_NETWORK_LOGS + ": makes all network logs available to " + - "the DPC and triggers DeviceAdminReceiver.onNetworkLogsAvailable() if needed.\n" + - "\n" + - "dpm " + COMMAND_FORCE_SECURITY_LOGS + ": makes all security logs available to " + - "the DPC and triggers DeviceAdminReceiver.onSecurityLogsAvailable() if needed." - + "\n" - + "usage: dpm " + COMMAND_MARK_PO_ON_ORG_OWNED_DEVICE + ": " - + "[ --user <USER_ID> | current ] <COMPONENT>\n"); - } - - @Override - public void onRun() throws Exception { - mDevicePolicyManager = IDevicePolicyManager.Stub.asInterface( - ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)); - if (mDevicePolicyManager == null) { - showError("Error: Could not access the Device Policy Manager. Is the system running?"); - return; - } - - String command = nextArgRequired(); - switch (command) { - case COMMAND_SET_ACTIVE_ADMIN: - runSetActiveAdmin(); - break; - case COMMAND_SET_DEVICE_OWNER: - runSetDeviceOwner(); - break; - case COMMAND_SET_PROFILE_OWNER: - runSetProfileOwner(); - break; - case COMMAND_REMOVE_ACTIVE_ADMIN: - runRemoveActiveAdmin(); - break; - case COMMAND_CLEAR_FREEZE_PERIOD_RECORD: - runClearFreezePeriodRecord(); - break; - case COMMAND_FORCE_NETWORK_LOGS: - runForceNetworkLogs(); - break; - case COMMAND_FORCE_SECURITY_LOGS: - runForceSecurityLogs(); - break; - case COMMAND_MARK_PO_ON_ORG_OWNED_DEVICE: - runMarkProfileOwnerOnOrganizationOwnedDevice(); - break; - default: - throw new IllegalArgumentException ("unknown command '" + command + "'"); - } - } - - private void runForceNetworkLogs() throws RemoteException, InterruptedException { - while (true) { - final long toWait = mDevicePolicyManager.forceNetworkLogs(); - if (toWait == 0) { - break; - } - System.out.println("We have to wait for " + toWait + " milliseconds..."); - Thread.sleep(toWait); - } - System.out.println("Success"); - } - - private void runForceSecurityLogs() throws RemoteException, InterruptedException { - while (true) { - final long toWait = mDevicePolicyManager.forceSecurityLogs(); - if (toWait == 0) { - break; - } - System.out.println("We have to wait for " + toWait + " milliseconds..."); - Thread.sleep(toWait); - } - System.out.println("Success"); - } - - private void parseArgs(boolean canHaveName) { - String opt; - while ((opt = nextOption()) != null) { - if ("--user".equals(opt)) { - String arg = nextArgRequired(); - if ("current".equals(arg) || "cur".equals(arg)) { - mUserId = UserHandle.USER_CURRENT; - } else { - mUserId = parseInt(arg); - } - if (mUserId == UserHandle.USER_CURRENT) { - IActivityManager activityManager = ActivityManager.getService(); - try { - mUserId = activityManager.getCurrentUser().id; - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - } else if (canHaveName && "--name".equals(opt)) { - mName = nextArgRequired(); - } else { - throw new IllegalArgumentException("Unknown option: " + opt); - } - } - mComponent = parseComponentName(nextArgRequired()); - } - - private void runSetActiveAdmin() throws RemoteException { - parseArgs(/*canHaveName=*/ false); - mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId); - - System.out.println("Success: Active admin set to component " + mComponent.toShortString()); - } - - private void runSetDeviceOwner() throws RemoteException { - parseArgs(/*canHaveName=*/ true); - mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId); - - try { - if (!mDevicePolicyManager.setDeviceOwner(mComponent, mName, mUserId)) { - throw new RuntimeException( - "Can't set package " + mComponent + " as device owner."); - } - } catch (Exception e) { - // Need to remove the admin that we just added. - mDevicePolicyManager.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM); - throw e; - } - - mDevicePolicyManager.setUserProvisioningState( - DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId); - - System.out.println("Success: Device owner set to package " + mComponent); - System.out.println("Active admin set to component " + mComponent.toShortString()); - } - - private void runRemoveActiveAdmin() throws RemoteException { - parseArgs(/*canHaveName=*/ false); - mDevicePolicyManager.forceRemoveActiveAdmin(mComponent, mUserId); - System.out.println("Success: Admin removed " + mComponent); - } - - private void runSetProfileOwner() throws RemoteException { - parseArgs(/*canHaveName=*/ true); - mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId); - - try { - if (!mDevicePolicyManager.setProfileOwner(mComponent, mName, mUserId)) { - throw new RuntimeException("Can't set component " + mComponent.toShortString() + - " as profile owner for user " + mUserId); - } - } catch (Exception e) { - // Need to remove the admin that we just added. - mDevicePolicyManager.removeActiveAdmin(mComponent, mUserId); - throw e; - } - - mDevicePolicyManager.setUserProvisioningState( - DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId); - - System.out.println("Success: Active admin and profile owner set to " - + mComponent.toShortString() + " for user " + mUserId); - } - - private void runClearFreezePeriodRecord() throws RemoteException { - mDevicePolicyManager.clearSystemUpdatePolicyFreezePeriodRecord(); - System.out.println("Success"); - } - - - private void runMarkProfileOwnerOnOrganizationOwnedDevice() throws RemoteException { - parseArgs(/*canHaveName=*/ false); - mDevicePolicyManager.markProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId); - System.out.println("Success"); - } - - private ComponentName parseComponentName(String component) { - ComponentName cn = ComponentName.unflattenFromString(component); - if (cn == null) { - throw new IllegalArgumentException ("Invalid component " + component); - } - return cn; - } - - private int parseInt(String argument) { - try { - return Integer.parseInt(argument); - } catch (NumberFormatException e) { - throw new IllegalArgumentException ("Invalid integer argument '" + argument + "'", e); - } - } -} diff --git a/cmds/idmap2/idmap2d/aidl/services/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/services/android/os/OverlayablePolicy.aidl index 403d8c55de16..a47b8416dbf5 100644 --- a/cmds/idmap2/idmap2d/aidl/services/android/os/OverlayablePolicy.aidl +++ b/cmds/idmap2/idmap2d/aidl/services/android/os/OverlayablePolicy.aidl @@ -20,14 +20,16 @@ package android.os; * @see ResourcesTypes.h ResTable_overlayable_policy_header::PolicyFlags * @hide */ -interface OverlayablePolicy { - const int PUBLIC = 0x00000001; - const int SYSTEM_PARTITION = 0x00000002; - const int VENDOR_PARTITION = 0x00000004; - const int PRODUCT_PARTITION = 0x00000008; - const int SIGNATURE = 0x00000010; - const int ODM_PARTITION = 0x00000020; - const int OEM_PARTITION = 0x00000040; - const int ACTOR_SIGNATURE = 0x00000080; - const int CONFIG_SIGNATURE = 0x0000100; +@Backing(type="int") +enum OverlayablePolicy { + NONE = 0x00000000, + PUBLIC = 0x00000001, + SYSTEM_PARTITION = 0x00000002, + VENDOR_PARTITION = 0x00000004, + PRODUCT_PARTITION = 0x00000008, + SIGNATURE = 0x00000010, + ODM_PARTITION = 0x00000020, + OEM_PARTITION = 0x00000040, + ACTOR_SIGNATURE = 0x00000080, + CONFIG_SIGNATURE = 0x0000100, } diff --git a/core/api/current.txt b/core/api/current.txt index 7cec886b5d99..bdeb2e2bc2c3 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -8014,7 +8014,6 @@ package android.app.job { method @Nullable public String[] getTriggeredContentAuthorities(); method @Nullable public android.net.Uri[] getTriggeredContentUris(); method public boolean isExpeditedJob(); - method @Deprecated public boolean isForegroundJob(); method public boolean isOverrideDeadlineExpired(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.job.JobParameters> CREATOR; @@ -9036,7 +9035,7 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getType(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.os.ParcelUuid[] getUuids(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setAlias(@NonNull String); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPairingConfirmation(boolean); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setPairingConfirmation(boolean); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setPin(byte[]); method public void writeToParcel(android.os.Parcel, int); field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED"; @@ -17137,11 +17136,11 @@ package android.graphics.text { package android.hardware { - public abstract class Battery { - ctor public Battery(); + public abstract class BatteryState { + ctor public BatteryState(); method @FloatRange(from=-1.0F, to=1.0f) public abstract float getCapacity(); method public abstract int getStatus(); - method public abstract boolean hasBattery(); + method public abstract boolean isPresent(); field public static final int STATUS_CHARGING = 2; // 0x2 field public static final int STATUS_DISCHARGING = 3; // 0x3 field public static final int STATUS_FULL = 5; // 0x5 @@ -18964,22 +18963,27 @@ package android.hardware.lights { method public int getType(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.Light> CREATOR; - field public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10; // 0xa - field public static final int LIGHT_TYPE_INPUT_RGB = 11; // 0xb - field public static final int LIGHT_TYPE_INPUT_SINGLE = 9; // 0x9 + field public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10002; // 0x2712 + field public static final int LIGHT_TYPE_INPUT_RGB = 10003; // 0x2713 + field public static final int LIGHT_TYPE_INPUT_SINGLE = 10001; // 0x2711 field public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8 } public final class LightState implements android.os.Parcelable { method public int describeContents(); - method @NonNull public static android.hardware.lights.LightState forColor(@ColorInt int); - method @NonNull public static android.hardware.lights.LightState forPlayerId(int); method @ColorInt public int getColor(); method public int getPlayerId(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.LightState> CREATOR; } + public static final class LightState.Builder { + ctor public LightState.Builder(); + method @NonNull public android.hardware.lights.LightState build(); + method @NonNull public android.hardware.lights.LightState.Builder setColor(@ColorInt int); + method @NonNull public android.hardware.lights.LightState.Builder setPlayerId(int); + } + public abstract class LightsManager { method @NonNull public abstract android.hardware.lights.LightState getLightState(@NonNull android.hardware.lights.Light); method @NonNull public abstract java.util.List<android.hardware.lights.Light> getLights(); @@ -18987,7 +18991,6 @@ package android.hardware.lights { } public abstract static class LightsManager.LightsSession implements java.lang.AutoCloseable { - ctor public LightsManager.LightsSession(); method public abstract void close(); method public abstract void requestLights(@NonNull android.hardware.lights.LightsRequest); } @@ -18995,6 +18998,7 @@ package android.hardware.lights { public final class LightsRequest { method @NonNull public java.util.List<android.hardware.lights.LightState> getLightStates(); method @NonNull public java.util.List<java.lang.Integer> getLights(); + method @NonNull public java.util.Map<java.lang.Integer,android.hardware.lights.LightState> getLightsAndStates(); } public static final class LightsRequest.Builder { @@ -19315,7 +19319,7 @@ package android.inputmethodservice { method public void appPrivateCommand(String, android.os.Bundle); method public void displayCompletions(android.view.inputmethod.CompletionInfo[]); method public void finishInput(); - method public void toggleSoftInput(int, int); + method @Deprecated public void toggleSoftInput(int, int); method public void updateCursor(android.graphics.Rect); method public void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo); method public void updateExtractedText(int, android.view.inputmethod.ExtractedText); @@ -26456,7 +26460,6 @@ package android.net { 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"; } @@ -26542,9 +26545,6 @@ package android.net { field public static final int UNSUPPORTED = -1; // 0xffffffff } - public interface TunnelConnectionParams { - } - 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); @@ -27109,16 +27109,16 @@ package android.net.vcn { method @NonNull public int[] getExposedCapabilities(); method @NonNull public String getGatewayConnectionName(); method @IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) public int getMaxMtu(); - method @NonNull public long[] getRetryIntervalsMs(); + method @NonNull public long[] getRetryIntervalsMillis(); } public static final class VcnGatewayConnectionConfig.Builder { - ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.TunnelConnectionParams); + ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.ipsec.ike.IkeTunnelConnectionParams); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build(); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) int); - method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryIntervalsMs(@NonNull long[]); + method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryIntervalsMillis(@NonNull long[]); } public class VcnManager { @@ -41989,7 +41989,6 @@ package android.telephony { method @IntRange(from=1, to=261) public int getBand(); method @IntRange(from=1) public int getCellBandwidthDownlinkKhz(); method @IntRange(from=1) public int getCellBandwidthUplinkKhz(); - method @Deprecated public int getChannelNumber(); method public int getConnectionStatus(); method @IntRange(from=0) public int getDownlinkChannelNumber(); method @IntRange(from=0) public int getDownlinkFrequencyKhz(); @@ -47130,7 +47129,7 @@ package android.view { public final class InputDevice implements android.os.Parcelable { method public int describeContents(); - method @NonNull public android.hardware.Battery getBattery(); + method @NonNull public android.hardware.BatteryState getBatteryState(); method public int getControllerNumber(); method public String getDescriptor(); method public static android.view.InputDevice getDevice(int); @@ -52000,8 +51999,8 @@ package android.view.inputmethod { method @Deprecated public void showStatusIcon(android.os.IBinder, String, @DrawableRes int); method @Deprecated public boolean switchToLastInputMethod(android.os.IBinder); method @Deprecated public boolean switchToNextInputMethod(android.os.IBinder, boolean); - method public void toggleSoftInput(int, int); - method public void toggleSoftInputFromWindow(android.os.IBinder, int, int); + method @Deprecated public void toggleSoftInput(int, int); + method @Deprecated public void toggleSoftInputFromWindow(android.os.IBinder, int, int); method @Deprecated public void updateCursor(android.view.View, int, int, int, int); method public void updateCursorAnchorInfo(android.view.View, android.view.inputmethod.CursorAnchorInfo); method public void updateExtractedText(android.view.View, int, android.view.inputmethod.ExtractedText); @@ -52024,7 +52023,7 @@ package android.view.inputmethod { method public void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback); method public void displayCompletions(android.view.inputmethod.CompletionInfo[]); method public void finishInput(); - method public void toggleSoftInput(int, int); + method @Deprecated public void toggleSoftInput(int, int); method public void updateCursor(android.graphics.Rect); method public void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo); method public void updateExtractedText(int, android.view.inputmethod.ExtractedText); @@ -52836,15 +52835,18 @@ package android.view.translation { } public final class TranslationManager { - method public void addOnDeviceTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent); + method public void addOnDeviceTranslationCapabilityUpdateListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.translation.TranslationCapability>); + method @Deprecated public void addOnDeviceTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent); method @Deprecated public void addTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent); - method @Nullable @WorkerThread public android.view.translation.Translator createOnDeviceTranslator(@NonNull android.view.translation.TranslationContext); + method public void createOnDeviceTranslator(@NonNull android.view.translation.TranslationContext, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.translation.Translator>); + method @Deprecated @Nullable @WorkerThread public android.view.translation.Translator createOnDeviceTranslator(@NonNull android.view.translation.TranslationContext); method @Deprecated @Nullable @WorkerThread public android.view.translation.Translator createTranslator(@NonNull android.view.translation.TranslationContext); method @NonNull @WorkerThread public java.util.Set<android.view.translation.TranslationCapability> getOnDeviceTranslationCapabilities(int, int); method @Nullable public android.app.PendingIntent getOnDeviceTranslationSettingsActivityIntent(); method @Deprecated @NonNull @WorkerThread public java.util.Set<android.view.translation.TranslationCapability> getTranslationCapabilities(int, int); method @Deprecated @Nullable public android.app.PendingIntent getTranslationSettingsActivityIntent(); - method public void removeOnDeviceTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent); + method public void removeOnDeviceTranslationCapabilityUpdateListener(@NonNull java.util.function.Consumer<android.view.translation.TranslationCapability>); + method @Deprecated public void removeOnDeviceTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent); method @Deprecated public void removeTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent); } @@ -56793,6 +56795,7 @@ package android.window { public interface SplashScreen { method public void clearOnExitAnimationListener(); method public void setOnExitAnimationListener(@NonNull android.window.SplashScreen.OnExitAnimationListener); + method public void setSplashScreenTheme(@StyleRes int); } public static interface SplashScreen.OnExitAnimationListener { diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 677da39f59f3..e48a1da7b6a7 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -223,9 +223,9 @@ package android.net { 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(); - method @NonNull public String getIface(); + method @NonNull public String getInterface(); method public int getOwnerUid(); - method @NonNull public java.util.List<java.lang.String> getUnderlyingIfaces(); + method @NonNull public java.util.List<java.lang.String> getUnderlyingInterfaces(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.UnderlyingNetworkInfo> CREATOR; } diff --git a/core/api/removed.txt b/core/api/removed.txt index ef35c593ed29..cdaa5f53eda0 100644 --- a/core/api/removed.txt +++ b/core/api/removed.txt @@ -252,6 +252,10 @@ package android.net { @IntDef({0x0, 0xa, 0x14, 0x1e}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NetworkBadging.Badging { } + public final class Proxy { + field @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO"; + } + @Deprecated public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory { method @Deprecated public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache); } diff --git a/core/api/system-current.txt b/core/api/system-current.txt index e74efd1d1482..ed141780b166 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -317,6 +317,7 @@ package android { public static final class R.attr { field public static final int allowClearUserDataOnFailedRestore = 16844288; // 0x1010600 + field public static final int durationBetweenRequestsMillis; field public static final int hotwordDetectionService; field public static final int isVrOnly = 16844152; // 0x1010578 field public static final int minExtensionVersion = 16844305; // 0x1010611 @@ -325,7 +326,6 @@ package android { field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566 field public static final int sdkVersion = 16844304; // 0x1010610 field public static final int supportsAmbientMode = 16844173; // 0x101058d - field public static final int throttleDurationMillis; field public static final int userRestriction = 16844164; // 0x1010584 } @@ -1448,11 +1448,12 @@ package android.app.prediction { package android.app.search { public final class Query implements android.os.Parcelable { - ctor public Query(@NonNull String, long, @Nullable android.os.Bundle); + ctor public Query(@NonNull String, long, @NonNull android.os.Bundle); + ctor public Query(@NonNull String, long); method public int describeContents(); - method @Nullable public android.os.Bundle getExtras(); + method @NonNull public android.os.Bundle getExtras(); method @NonNull public String getInput(); - method @NonNull public long getTimestamp(); + method public long getTimestampMillis(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.search.Query> CREATOR; } @@ -1485,9 +1486,10 @@ package android.app.search { } public final class SearchContext implements android.os.Parcelable { - ctor public SearchContext(int, int, @Nullable android.os.Bundle); + ctor public SearchContext(int, int); + ctor public SearchContext(int, int, @NonNull android.os.Bundle); method public int describeContents(); - method @Nullable public android.os.Bundle getExtras(); + method @NonNull public android.os.Bundle getExtras(); method @Nullable public String getPackageName(); method @NonNull public int getResultTypes(); method @NonNull public int getTimeoutMillis(); @@ -1497,7 +1499,6 @@ package android.app.search { public final class SearchSession implements java.lang.AutoCloseable { method public void close(); - method public void destroy(); method protected void finalize(); method public void notifyEvent(@NonNull android.app.search.Query, @NonNull android.app.search.SearchTargetEvent); method @Nullable public void query(@NonNull android.app.search.Query, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.search.SearchTarget>>); @@ -1512,7 +1513,7 @@ package android.app.search { public final class SearchTarget implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.appwidget.AppWidgetProviderInfo getAppWidgetProviderInfo(); - method @Nullable public android.os.Bundle getExtras(); + method @NonNull public android.os.Bundle getExtras(); method @NonNull public String getId(); method @NonNull public String getLayoutType(); method @NonNull public String getPackageName(); @@ -1526,13 +1527,17 @@ package android.app.search { method public boolean shouldHide(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.search.SearchTarget> CREATOR; + field public static final int RESULT_TYPE_APPLICATION = 1; // 0x1 + field public static final int RESULT_TYPE_SHORTCUT = 2; // 0x2 + field public static final int RESULT_TYPE_SLICE = 4; // 0x4 + field public static final int RESULT_TYPE_WIDGETS = 8; // 0x8 } public static final class SearchTarget.Builder { ctor public SearchTarget.Builder(int, @NonNull String, @NonNull String); method @NonNull public android.app.search.SearchTarget build(); method @NonNull public android.app.search.SearchTarget.Builder setAppWidgetProviderInfo(@NonNull android.appwidget.AppWidgetProviderInfo); - method @NonNull public android.app.search.SearchTarget.Builder setExtras(@Nullable android.os.Bundle); + method @NonNull public android.app.search.SearchTarget.Builder setExtras(@NonNull android.os.Bundle); method @NonNull public android.app.search.SearchTarget.Builder setPackageName(@NonNull String); method @NonNull public android.app.search.SearchTarget.Builder setParentId(@NonNull String); method @NonNull public android.app.search.SearchTarget.Builder setScore(float); @@ -1925,16 +1930,16 @@ package android.bluetooth { } public final class BluetoothAdapter { - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disableBLE(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableBLE(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableNoAutoConnect(); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void generateLocalOobData(int, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OobDataCallback); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public long getDiscoveryEndMillis(); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void generateLocalOobData(int, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OobDataCallback); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public long getDiscoveryEndMillis(); method public boolean isBleScanAlwaysAvailable(); method public boolean isLeEnabled(); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean removeActiveDevice(int); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setActiveDevice(@NonNull android.bluetooth.BluetoothDevice, int); field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE"; @@ -1952,24 +1957,24 @@ package android.bluetooth { public static interface BluetoothAdapter.OobDataCallback { method public void onError(int); - method public void onOobData(int, @Nullable android.bluetooth.OobData); + method public void onOobData(int, @NonNull android.bluetooth.OobData); } public final class BluetoothDevice implements android.os.Parcelable { - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean canBondWithoutDialog(); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean canBondWithoutDialog(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean cancelBondProcess(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData); - method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int); + method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public byte[] getMetadata(int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getSimAccessPermission(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isConnected(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isEncrypted(); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode(); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean isInSilenceMode(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeBond(); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMessageAccessPermission(int); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean); - method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSimAccessPermission(int); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setMessageAccessPermission(int); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setMetadata(int, @NonNull byte[]); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setPhonebookAccessPermission(int); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setSilenceMode(boolean); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setSimAccessPermission(int); field public static final int ACCESS_ALLOWED = 1; // 0x1 field public static final int ACCESS_REJECTED = 2; // 0x2 field public static final int ACCESS_UNKNOWN = 0; // 0x0 @@ -2135,8 +2140,6 @@ package android.bluetooth { } public final class OobData implements android.os.Parcelable { - method @NonNull public static android.bluetooth.OobData.ClassicBuilder createClassicBuilder(@NonNull byte[], @NonNull byte[], @NonNull byte[]); - method @NonNull public static android.bluetooth.OobData.LeBuilder createLeBuilder(@NonNull byte[], @NonNull byte[], int); method @NonNull public byte[] getClassOfDevice(); method @NonNull public byte[] getClassicLength(); method @NonNull public byte[] getConfirmationHash(); @@ -2169,6 +2172,7 @@ package android.bluetooth { } public static final class OobData.ClassicBuilder { + ctor public OobData.ClassicBuilder(@NonNull byte[], @NonNull byte[], @NonNull byte[]); method @NonNull public android.bluetooth.OobData build(); method @NonNull public android.bluetooth.OobData.ClassicBuilder setClassOfDevice(@NonNull byte[]); method @NonNull public android.bluetooth.OobData.ClassicBuilder setDeviceName(@NonNull byte[]); @@ -2176,6 +2180,7 @@ package android.bluetooth { } public static final class OobData.LeBuilder { + ctor public OobData.LeBuilder(@NonNull byte[], @NonNull byte[], int); method @NonNull public android.bluetooth.OobData build(); method @NonNull public android.bluetooth.OobData.LeBuilder setDeviceName(@NonNull byte[]); method @NonNull public android.bluetooth.OobData.LeBuilder setLeFlags(int); @@ -2752,6 +2757,7 @@ package android.content.pm { field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40 field public static final int FLAG_PERMISSION_REVOKED_COMPAT = 8; // 0x8 field @Deprecated public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8 + field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80 field public static final int FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY = 524288; // 0x80000 field public static final int FLAG_PERMISSION_SYSTEM_FIXED = 16; // 0x10 field public static final int FLAG_PERMISSION_USER_FIXED = 2; // 0x2 @@ -8831,8 +8837,8 @@ package android.permission { public final class PermissionControllerManager { method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); - method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING) public void getGroupOfPlatformPermission(@NonNull String, @NonNull java.util.function.Consumer<java.lang.String>); - method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING) public void getPlatformPermissionsForGroup(@NonNull String, @NonNull java.util.function.Consumer<java.util.List<java.lang.String>>); + method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING) public void getGroupOfPlatformPermission(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.String>); + method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING) public void getPlatformPermissionsForGroup(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<java.lang.String>>); method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>); method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback); method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle); @@ -9867,7 +9873,7 @@ package android.service.displayhash { public final class DisplayHashParams implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.util.Size getBufferSize(); - method public boolean isUseGrayscale(); + method public boolean isGrayscaleBuffer(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.displayhash.DisplayHashParams> CREATOR; } @@ -9876,7 +9882,7 @@ package android.service.displayhash { ctor public DisplayHashParams.Builder(); method @NonNull public android.service.displayhash.DisplayHashParams build(); method @NonNull public android.service.displayhash.DisplayHashParams.Builder setBufferSize(int, int); - method @NonNull public android.service.displayhash.DisplayHashParams.Builder setUseGrayscale(boolean); + method @NonNull public android.service.displayhash.DisplayHashParams.Builder setGrayscaleBuffer(boolean); } public abstract class DisplayHashingService extends android.app.Service { @@ -10260,10 +10266,10 @@ package android.service.search { public abstract class SearchUiService extends android.app.Service { ctor public SearchUiService(); method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); - method public void onCreateSearchSession(@NonNull android.app.search.SearchContext, @NonNull android.app.search.SearchSessionId); method @MainThread public abstract void onDestroy(@NonNull android.app.search.SearchSessionId); method @MainThread public abstract void onNotifyEvent(@NonNull android.app.search.SearchSessionId, @NonNull android.app.search.Query, @NonNull android.app.search.SearchTargetEvent); method @MainThread public abstract void onQuery(@NonNull android.app.search.SearchSessionId, @NonNull android.app.search.Query, @NonNull java.util.function.Consumer<java.util.List<android.app.search.SearchTarget>>); + method public void onSearchSessionCreated(@NonNull android.app.search.SearchContext, @NonNull android.app.search.SearchSessionId); } } @@ -10513,6 +10519,7 @@ package android.service.voice { method public static int getMaxBundleSize(); method public static int getMaxHotwordPhraseId(); method public static int getMaxScore(); + method @Nullable public android.media.MediaSyncEvent getMediaSyncEvent(); method public int getPersonalizedScore(); method public int getScore(); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -10527,6 +10534,7 @@ package android.service.voice { method @NonNull public android.service.voice.HotwordDetectedResult.Builder setConfidenceLevel(int); method @NonNull public android.service.voice.HotwordDetectedResult.Builder setExtras(@NonNull android.os.PersistableBundle); method @NonNull public android.service.voice.HotwordDetectedResult.Builder setHotwordPhraseId(int); + method @NonNull public android.service.voice.HotwordDetectedResult.Builder setMediaSyncEvent(@NonNull android.media.MediaSyncEvent); method @NonNull public android.service.voice.HotwordDetectedResult.Builder setPersonalizedScore(int); method @NonNull public android.service.voice.HotwordDetectedResult.Builder setScore(int); } @@ -10534,8 +10542,10 @@ package android.service.voice { 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 onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.Callback); - method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @NonNull android.service.voice.HotwordDetectionService.Callback); + method @Deprecated public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.Callback); + method public void onDetect(@NonNull android.service.voice.AlwaysOnHotwordDetector.EventPayload, long, @NonNull android.service.voice.HotwordDetectionService.Callback); + method @Deprecated public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @NonNull android.service.voice.HotwordDetectionService.Callback); + method public void onDetect(@NonNull android.service.voice.HotwordDetectionService.Callback); method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle, @NonNull android.service.voice.HotwordDetectionService.Callback); method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, long, @Nullable java.util.function.IntConsumer); field public static final int INITIALIZATION_STATUS_CUSTOM_ERROR_1 = 1; // 0x1 @@ -10581,7 +10591,8 @@ package android.service.voice { public class VoiceInteractionService extends android.app.Service { method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, android.service.voice.AlwaysOnHotwordDetector.Callback); - method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull android.service.voice.HotwordDetector.Callback); + method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull android.service.voice.HotwordDetector.Callback); + method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull android.service.voice.HotwordDetector.Callback); method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager(); } @@ -14519,7 +14530,21 @@ package android.view.translation { method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void finishTranslation(@NonNull android.app.assist.ActivityId); method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void pauseTranslation(@NonNull android.app.assist.ActivityId); method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void resumeTranslation(@NonNull android.app.assist.ActivityId); - method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, @NonNull android.app.assist.ActivityId); + method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, @NonNull android.app.assist.ActivityId); + method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, @NonNull android.app.assist.ActivityId, @NonNull android.view.translation.UiTranslationSpec); + } + + public final class UiTranslationSpec implements android.os.Parcelable { + method public int describeContents(); + method public boolean shouldPadContentForCompat(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.UiTranslationSpec> CREATOR; + } + + public static final class UiTranslationSpec.Builder { + ctor public UiTranslationSpec.Builder(); + method @NonNull public android.view.translation.UiTranslationSpec build(); + method @NonNull public android.view.translation.UiTranslationSpec.Builder setShouldPadContentForCompat(boolean); } } diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt index f366a54596e2..65a87808b7b1 100644 --- a/core/api/system-removed.txt +++ b/core/api/system-removed.txt @@ -48,6 +48,18 @@ package android.app.prediction { } +package android.app.search { + + public final class Query implements android.os.Parcelable { + method @Deprecated @NonNull public long getTimestamp(); + } + + public final class SearchSession implements java.lang.AutoCloseable { + method @Deprecated public void destroy(); + } + +} + package android.bluetooth { public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile { @@ -163,6 +175,14 @@ package android.service.notification { } +package android.service.search { + + public abstract class SearchUiService extends android.app.Service { + method @Deprecated public void onCreateSearchSession(@NonNull android.app.search.SearchContext, @NonNull android.app.search.SearchSessionId); + } + +} + package android.telecom { public class TelecomManager { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index d8c138759cf0..61a9954c6336 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -382,6 +382,7 @@ package android.app { method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle); method public void syncInputTransactions(); method public void syncInputTransactions(boolean); + method @Nullable public android.graphics.Bitmap takeScreenshot(@NonNull android.view.Window); field @NonNull public static final java.util.Set<java.lang.String> ALL_PERMISSIONS; } @@ -2102,6 +2103,7 @@ package android.provider { field public static final String AUTOMATIC_POWER_SAVE_MODE = "automatic_power_save_mode"; field public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants"; field public static final String DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW = "enable_non_resizable_multi_window"; + field public static final String DISABLE_WINDOW_BLURS = "disable_window_blurs"; field public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold"; field public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled"; field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions"; @@ -2672,6 +2674,12 @@ package android.view { public final class ContentInfo { method @NonNull public android.util.Pair<android.view.ContentInfo,android.view.ContentInfo> partition(@NonNull java.util.function.Predicate<android.content.ClipData.Item>); + method public void releasePermissions(); + } + + public static final class ContentInfo.Builder { + method @NonNull public android.view.ContentInfo.Builder setDragAndDropPermissions(@Nullable android.view.DragAndDropPermissions); + method @NonNull public android.view.ContentInfo.Builder setInputContentInfo(@Nullable android.view.inputmethod.InputContentInfo); } public final class Display { @@ -2779,7 +2787,6 @@ package android.view { method public default void holdLock(android.os.IBinder, int); method public default boolean isTaskSnapshotSupported(); method public default void setDisplayImePolicy(int, int); - method public default void setForceCrossWindowBlurDisabled(boolean); method public default void setShouldShowSystemDecors(int, boolean); method public default void setShouldShowWithInsecureKeyguard(int, boolean); method public default boolean shouldShowSystemDecors(int); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index a24555f79a1c..6d2d0238ed37 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1947,8 +1947,9 @@ public class ActivityManager { pw.print(((baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0)); pw.print(" activityType="); pw.print(activityTypeToString(getActivityType())); pw.print(" windowingMode="); pw.print(windowingModeToString(getWindowingMode())); - pw.print(" supportsSplitScreenMultiWindow="); - pw.println(supportsSplitScreenMultiWindow); + pw.print(" supportsSplitScreenMultiWindow="); pw.print(supportsSplitScreenMultiWindow); + pw.print(" supportsMultiWindow="); + pw.println(supportsMultiWindow); if (taskDescription != null) { pw.print(" "); final ActivityManager.TaskDescription td = taskDescription; diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java index 6df9f4da7ae8..4a7fcd232ce9 100644 --- a/core/java/android/app/ActivityTaskManager.java +++ b/core/java/android/app/ActivityTaskManager.java @@ -349,20 +349,6 @@ public class ActivityTaskManager { } /** - * 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. - * @hide - */ - public static boolean supportsNonResizableMultiWindow() { - try { - return ActivityTaskManager.getService().supportsNonResizableMultiWindow(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * @return whether the UI mode of the given config supports error dialogs (ANR, crash, etc). * @hide */ diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 6e0b83f7e33c..8f645c893a1c 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4416,11 +4416,20 @@ public final class ActivityThread extends ClientTransactionHandler if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name); Application app = packageInfo.makeApplication(false, mInstrumentation); - java.lang.ClassLoader cl = packageInfo.getClassLoader(); + + final java.lang.ClassLoader cl; + if (data.info.splitName != null) { + cl = packageInfo.getSplitClassLoader(data.info.splitName); + } else { + cl = packageInfo.getClassLoader(); + } service = packageInfo.getAppFactory() .instantiateService(cl, data.info.name, data.intent); - final ContextImpl context = ContextImpl.getImpl(service + ContextImpl context = ContextImpl.getImpl(service .createServiceBaseContext(this, packageInfo)); + if (data.info.splitName != null) { + context = (ContextImpl) context.createContextForSplit(data.info.splitName); + } // Service resources must be initialized with the same loaders as the application // context. context.getResources().addLoaders( diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 1cb46b1b6350..d7986201c02b 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -6511,13 +6511,21 @@ public class AppOpsManager { NoteOpEvent note = new NoteOpEvent(discreteAccessTime, discreteAccessDuration, null); accessEvents.append(key, note); AttributedOpEntry access = new AttributedOpEntry(mOp, false, accessEvents, null); - for (int i = discreteAccesses.size() - 1; i >= 0; i--) { - if (discreteAccesses.get(i).getLastAccessTime(OP_FLAGS_ALL) < discreteAccessTime) { - discreteAccesses.add(i + 1, access); - return; + int insertionPoint = discreteAccesses.size() - 1; + for (; insertionPoint >= 0; insertionPoint--) { + if (discreteAccesses.get(insertionPoint).getLastAccessTime(OP_FLAGS_ALL) + < discreteAccessTime) { + break; } } - discreteAccesses.add(0, access); + insertionPoint++; + if (insertionPoint < discreteAccesses.size() && discreteAccesses.get( + insertionPoint).getLastAccessTime(OP_FLAGS_ALL) == discreteAccessTime) { + discreteAccesses.set(insertionPoint, mergeAttributedOpEntries( + Arrays.asList(discreteAccesses.get(insertionPoint), access))); + } else { + discreteAccesses.add(insertionPoint, access); + } } /** @@ -9858,7 +9866,10 @@ public class AppOpsManager { NoteOpEvent reject = a.getLastRejectEvent(uidState, uidState, flags); if (access != null) { - accessEvents.append(key, access); + NoteOpEvent existingAccess = accessEvents.get(key); + if (existingAccess == null || existingAccess.getDuration() == -1) { + accessEvents.append(key, access); + } } if (reject != null) { rejectEvents.append(key, reject); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 656942d315cc..9ce37e48ce19 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -3273,6 +3273,13 @@ class ContextImpl extends Context { dir = null; } } + if (dir != null && !dir.canWrite()) { + // Older versions of the MediaProvider mainline module had a rare early boot race + // condition where app-private dirs could be created with the wrong permissions; + // fix this up here. This check should be very fast, because dir.exists() above + // will already have loaded the dentry in the cache. + sm.fixupAppDir(dir); + } result[i] = dir; } return result; diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index b75e89ce6fda..74d51a0bcf63 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -259,13 +259,6 @@ interface IActivityTaskManager { void setSplitScreenResizing(boolean resizing); boolean supportsLocalVoiceInteraction(); - /** - * 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. - */ - boolean supportsNonResizableMultiWindow(); - // Get device configuration ConfigurationInfo getDeviceConfigurationInfo(); diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl index c30bc248344c..623af5f90749 100644 --- a/core/java/android/app/IUiAutomationConnection.aidl +++ b/core/java/android/app/IUiAutomationConnection.aidl @@ -20,6 +20,7 @@ import android.accessibilityservice.IAccessibilityServiceClient; import android.graphics.Bitmap; import android.graphics.Rect; import android.view.InputEvent; +import android.view.SurfaceControl; import android.view.WindowContentFrameStats; import android.view.WindowAnimationFrameStats; import android.os.ParcelFileDescriptor; @@ -42,6 +43,7 @@ interface IUiAutomationConnection { void syncInputTransactions(boolean waitForAnimations); boolean setRotation(int rotation); Bitmap takeScreenshot(in Rect crop); + Bitmap takeSurfaceControlScreenshot(in SurfaceControl surfaceControl); boolean clearWindowContentFrameStats(int windowId); WindowContentFrameStats getWindowContentFrameStats(int windowId); void clearWindowAnimationFrameStats(); diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 83d0246744df..ea6c87493316 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -58,6 +58,7 @@ import android.util.Slog; import android.util.SparseArray; import android.view.DisplayAdjustments; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import dalvik.system.BaseDexClassLoader; @@ -156,6 +157,7 @@ public final class LoadedApk { private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices = new ArrayMap<>(); private AppComponentFactory mAppComponentFactory; + private final Object mLock = new Object(); Application getApplication() { return mApplication; @@ -354,7 +356,7 @@ public final class LoadedApk { } else { addedPaths.addAll(newPaths); } - synchronized (this) { + synchronized (mLock) { createOrUpdateClassLoaderLocked(addedPaths); if (mResources != null) { final String[] splitPaths; @@ -589,7 +591,9 @@ public final class LoadedApk { * include the base APK in the list of splits. */ private class SplitDependencyLoaderImpl extends SplitDependencyLoader<NameNotFoundException> { + @GuardedBy("mLock") private final String[][] mCachedResourcePaths; + @GuardedBy("mLock") private final ClassLoader[] mCachedClassLoaders; SplitDependencyLoaderImpl(@NonNull SparseArray<int[]> dependencies) { @@ -600,37 +604,41 @@ public final class LoadedApk { @Override protected boolean isSplitCached(int splitIdx) { - return mCachedClassLoaders[splitIdx] != null; + synchronized (mLock) { + return mCachedClassLoaders[splitIdx] != null; + } } @Override protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices, int parentSplitIdx) throws NameNotFoundException { - final ArrayList<String> splitPaths = new ArrayList<>(); - if (splitIdx == 0) { - createOrUpdateClassLoaderLocked(null); - mCachedClassLoaders[0] = mClassLoader; + synchronized (mLock) { + final ArrayList<String> splitPaths = new ArrayList<>(); + if (splitIdx == 0) { + createOrUpdateClassLoaderLocked(null); + mCachedClassLoaders[0] = mClassLoader; + + // Never add the base resources here, they always get added no matter what. + for (int configSplitIdx : configSplitIndices) { + splitPaths.add(mSplitResDirs[configSplitIdx - 1]); + } + mCachedResourcePaths[0] = splitPaths.toArray(new String[splitPaths.size()]); + return; + } + + // Since we handled the special base case above, parentSplitIdx is always valid. + final ClassLoader parent = mCachedClassLoaders[parentSplitIdx]; + mCachedClassLoaders[splitIdx] = ApplicationLoaders.getDefault().getClassLoader( + mSplitAppDirs[splitIdx - 1], getTargetSdkVersion(), false, null, + null, parent, mSplitClassLoaderNames[splitIdx - 1]); - // Never add the base resources here, they always get added no matter what. + Collections.addAll(splitPaths, mCachedResourcePaths[parentSplitIdx]); + splitPaths.add(mSplitResDirs[splitIdx - 1]); for (int configSplitIdx : configSplitIndices) { splitPaths.add(mSplitResDirs[configSplitIdx - 1]); } - mCachedResourcePaths[0] = splitPaths.toArray(new String[splitPaths.size()]); - return; + mCachedResourcePaths[splitIdx] = splitPaths.toArray(new String[splitPaths.size()]); } - - // Since we handled the special base case above, parentSplitIdx is always valid. - final ClassLoader parent = mCachedClassLoaders[parentSplitIdx]; - mCachedClassLoaders[splitIdx] = ApplicationLoaders.getDefault().getClassLoader( - mSplitAppDirs[splitIdx - 1], getTargetSdkVersion(), false, null, null, parent, - mSplitClassLoaderNames[splitIdx - 1]); - - Collections.addAll(splitPaths, mCachedResourcePaths[parentSplitIdx]); - splitPaths.add(mSplitResDirs[splitIdx - 1]); - for (int configSplitIdx : configSplitIndices) { - splitPaths.add(mSplitResDirs[configSplitIdx - 1]); - } - mCachedResourcePaths[splitIdx] = splitPaths.toArray(new String[splitPaths.size()]); } private int ensureSplitLoaded(String splitName) throws NameNotFoundException { @@ -648,11 +656,17 @@ public final class LoadedApk { } ClassLoader getClassLoaderForSplit(String splitName) throws NameNotFoundException { - return mCachedClassLoaders[ensureSplitLoaded(splitName)]; + final int idx = ensureSplitLoaded(splitName); + synchronized (mLock) { + return mCachedClassLoaders[idx]; + } } String[] getSplitPathsForSplit(String splitName) throws NameNotFoundException { - return mCachedResourcePaths[ensureSplitLoaded(splitName)]; + final int idx = ensureSplitLoaded(splitName); + synchronized (mLock) { + return mCachedResourcePaths[idx]; + } } } @@ -749,6 +763,7 @@ public final class LoadedApk { } } + @GuardedBy("mLock") private void createOrUpdateClassLoaderLocked(List<String> addedPaths) { if (mPackageName.equals("android")) { // Note: This branch is taken for system server and we don't need to setup @@ -1023,7 +1038,7 @@ public final class LoadedApk { @UnsupportedAppUsage public ClassLoader getClassLoader() { - synchronized (this) { + synchronized (mLock) { if (mClassLoader == null) { createOrUpdateClassLoaderLocked(null /*addedPaths*/); } diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 6ad5eea8b602..b95412f00453 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -138,6 +138,13 @@ public class TaskInfo { public boolean supportsSplitScreenMultiWindow; /** + * Whether this task supports multi windowing modes based on the device settings and the + * root activity resizability and configuration. + * @hide + */ + public boolean supportsMultiWindow; + + /** * The resize mode of the task. See {@link ActivityInfo#resizeMode}. * @hide */ @@ -329,6 +336,7 @@ public class TaskInfo { } return topActivityType == that.topActivityType && isResizeable == that.isResizeable + && supportsMultiWindow == that.supportsMultiWindow && Objects.equals(positionInParent, that.positionInParent) && Objects.equals(pictureInPictureParams, that.pictureInPictureParams) && getWindowingMode() == that.getWindowingMode() @@ -375,6 +383,7 @@ public class TaskInfo { taskDescription = source.readTypedObject(ActivityManager.TaskDescription.CREATOR); supportsSplitScreenMultiWindow = source.readBoolean(); + supportsMultiWindow = source.readBoolean(); resizeMode = source.readInt(); configuration.readFromParcel(source); token = WindowContainerToken.CREATOR.createFromParcel(source); @@ -412,6 +421,7 @@ public class TaskInfo { dest.writeTypedObject(taskDescription, flags); dest.writeBoolean(supportsSplitScreenMultiWindow); + dest.writeBoolean(supportsMultiWindow); dest.writeInt(resizeMode); configuration.writeToParcel(dest, flags); token.writeToParcel(dest, flags); @@ -440,6 +450,7 @@ public class TaskInfo { + " numActivities=" + numActivities + " lastActiveTime=" + lastActiveTime + " supportsSplitScreenMultiWindow=" + supportsSplitScreenMultiWindow + + " supportsMultiWindow=" + supportsMultiWindow + " resizeMode=" + resizeMode + " isResizeable=" + isResizeable + " token=" + token diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 7d3db5e2cc49..e0b484cca828 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -50,6 +50,10 @@ import android.view.Display; import android.view.InputEvent; import android.view.KeyEvent; import android.view.Surface; +import android.view.SurfaceControl; +import android.view.View; +import android.view.ViewRootImpl; +import android.view.Window; import android.view.WindowAnimationFrameStats; import android.view.WindowContentFrameStats; import android.view.accessibility.AccessibilityEvent; @@ -1012,7 +1016,7 @@ public final class UiAutomation { return null; } } catch (RemoteException re) { - Log.e(LOG_TAG, "Error while taking screnshot!", re); + Log.e(LOG_TAG, "Error while taking screenshot!", re); return null; } @@ -1023,6 +1027,51 @@ public final class UiAutomation { } /** + * Used to capture a screenshot of a Window. This can return null in the following cases: + * 1. Window content hasn't been layed out. + * 2. Window doesn't have a valid SurfaceControl + * 3. An error occurred in SurfaceFlinger when trying to take the screenshot. + * + * @param window Window to take a screenshot of + * + * @return The screenshot bitmap on success, null otherwise. + * + * @hide + */ + @TestApi + @Nullable + public Bitmap takeScreenshot(@NonNull Window window) { + if (window == null) { + return null; + } + + View decorView = window.peekDecorView(); + if (decorView == null) { + return null; + } + + ViewRootImpl viewRoot = decorView.getViewRootImpl(); + if (viewRoot == null) { + return null; + } + + SurfaceControl sc = viewRoot.getSurfaceControl(); + if (!sc.isValid()) { + return null; + } + + // Apply a sync transaction to ensure SurfaceFlinger is flushed before capturing a + // screenshot. + new SurfaceControl.Transaction().apply(true); + try { + return mUiAutomationConnection.takeSurfaceControlScreenshot(sc); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error while taking screenshot!", re); + return null; + } + } + + /** * Sets whether this UiAutomation to run in a "monkey" mode. Applications can query whether * they are executed in a "monkey" mode, i.e. run by a test framework, and avoid doing * potentially undesirable actions such as calling 911 or posting on public forums etc. diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index 90210a9a2756..e693c5ea6c93 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -18,6 +18,7 @@ package android.app; import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.IAccessibilityServiceClient; +import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -206,6 +207,30 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { } } + @Nullable + @Override + public Bitmap takeSurfaceControlScreenshot(@NonNull SurfaceControl surfaceControl) { + synchronized (mLock) { + throwIfCalledByNotTrustedUidLocked(); + throwIfShutdownLocked(); + throwIfNotConnectedLocked(); + } + + SurfaceControl.ScreenshotHardwareBuffer captureBuffer; + final long identity = Binder.clearCallingIdentity(); + try { + captureBuffer = SurfaceControl.captureLayers( + new SurfaceControl.LayerCaptureArgs.Builder(surfaceControl).build()); + } finally { + Binder.restoreCallingIdentity(identity); + } + + if (captureBuffer == null) { + return null; + } + return captureBuffer.asBitmap(); + } + @Override public boolean clearWindowContentFrameStats(int windowId) throws RemoteException { synchronized (mLock) { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index c93a88f9f312..cbf2d6a12bec 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -10368,6 +10368,9 @@ public class DevicePolicyManager { /** * Called by device owners to set the user's global location setting. * + * <p><b>Note: </b> this call is ignored on + * {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}. + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with * @param locationEnabled whether location should be enabled or disabled * @throws SecurityException if {@code admin} is not a device owner. diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java index 759597ce36dc..4c1a36340d5d 100644 --- a/core/java/android/app/admin/PasswordMetrics.java +++ b/core/java/android/app/admin/PasswordMetrics.java @@ -531,7 +531,7 @@ public final class PasswordMetrics implements Parcelable { } final PasswordMetrics enteredMetrics = computeForPasswordOrPin(password, isPin); - return validatePasswordMetrics(adminMetrics, minComplexity, isPin, enteredMetrics); + return validatePasswordMetrics(adminMetrics, minComplexity, enteredMetrics); } /** @@ -539,15 +539,13 @@ public final class PasswordMetrics implements Parcelable { * * @param adminMetrics - minimum metrics to satisfy admin requirements. * @param minComplexity - minimum complexity imposed by the requester. - * @param isPin - whether it is PIN that should be only digits * @param actualMetrics - metrics for password to validate. * @return a list of password validation errors. An empty list means the password is OK. * * TODO: move to PasswordPolicy */ public static List<PasswordValidationError> validatePasswordMetrics( - PasswordMetrics adminMetrics, int minComplexity, boolean isPin, - PasswordMetrics actualMetrics) { + PasswordMetrics adminMetrics, int minComplexity, PasswordMetrics actualMetrics) { final ComplexityBucket bucket = ComplexityBucket.forComplexity(minComplexity); // Make sure credential type is satisfactory. @@ -561,7 +559,7 @@ public final class PasswordMetrics implements Parcelable { return Collections.emptyList(); // Nothing to check for pattern or none. } - if (isPin && actualMetrics.nonNumeric > 0) { + if (actualMetrics.credType == CREDENTIAL_TYPE_PIN && actualMetrics.nonNumeric > 0) { return Collections.singletonList( new PasswordValidationError(CONTAINS_INVALID_CHARACTERS, 0)); } diff --git a/core/java/android/app/compat/PackageOverride.java b/core/java/android/app/compat/PackageOverride.java index 59b355523a30..fad6cd311021 100644 --- a/core/java/android/app/compat/PackageOverride.java +++ b/core/java/android/app/compat/PackageOverride.java @@ -19,6 +19,7 @@ package android.app.compat; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.content.pm.PackageInfo; import android.os.Parcel; import java.lang.annotation.Retention; @@ -101,12 +102,20 @@ public final class PackageOverride { return VALUE_UNDEFINED; } - /** Returns the minimum version code the override applies to. */ + /** + * Returns the minimum APK version code the override applies to. + * + * @see PackageInfo#getLongVersionCode() + */ public long getMinVersionCode() { return mMinVersionCode; } - /** Returns the minimum version code the override applies from. */ + /** + * Returns the maximum APK version code the override applies from. + * + * @see PackageInfo#getLongVersionCode() + */ public long getMaxVersionCode() { return mMaxVersionCode; } @@ -146,9 +155,11 @@ public final class PackageOverride { private boolean mEnabled; /** - * Sets the minimum version code the override should apply from. + * Sets the minimum APK version code the override should apply from. * * default value: {@code Long.MIN_VALUE}. + * + * @see PackageInfo#getLongVersionCode() */ @NonNull public Builder setMinVersionCode(long minVersionCode) { @@ -157,9 +168,11 @@ public final class PackageOverride { } /** - * Sets the maximum version code the override should apply to. + * Sets the maximum APK version code the override should apply to. * * default value: {@code Long.MAX_VALUE}. + * + * @see PackageInfo#getLongVersionCode() */ @NonNull public Builder setMaxVersionCode(long maxVersionCode) { diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java index 8866c767a606..de3eeee281ac 100644 --- a/core/java/android/app/people/PeopleSpaceTile.java +++ b/core/java/android/app/people/PeopleSpaceTile.java @@ -54,6 +54,7 @@ public class PeopleSpaceTile implements Parcelable { private boolean mIsImportantConversation; private String mNotificationKey; private CharSequence mNotificationContent; + private CharSequence mNotificationSender; private String mNotificationCategory; private Uri mNotificationDataUri; private int mMessagesCount; @@ -73,6 +74,7 @@ public class PeopleSpaceTile implements Parcelable { mIsImportantConversation = b.mIsImportantConversation; mNotificationKey = b.mNotificationKey; mNotificationContent = b.mNotificationContent; + mNotificationSender = b.mNotificationSender; mNotificationCategory = b.mNotificationCategory; mNotificationDataUri = b.mNotificationDataUri; mMessagesCount = b.mMessagesCount; @@ -134,6 +136,10 @@ public class PeopleSpaceTile implements Parcelable { return mNotificationContent; } + public CharSequence getNotificationSender() { + return mNotificationSender; + } + public String getNotificationCategory() { return mNotificationCategory; } @@ -179,6 +185,7 @@ public class PeopleSpaceTile implements Parcelable { builder.setIsImportantConversation(mIsImportantConversation); builder.setNotificationKey(mNotificationKey); builder.setNotificationContent(mNotificationContent); + builder.setNotificationSender(mNotificationSender); builder.setNotificationCategory(mNotificationCategory); builder.setNotificationDataUri(mNotificationDataUri); builder.setMessagesCount(mMessagesCount); @@ -201,6 +208,7 @@ public class PeopleSpaceTile implements Parcelable { private boolean mIsImportantConversation; private String mNotificationKey; private CharSequence mNotificationContent; + private CharSequence mNotificationSender; private String mNotificationCategory; private Uri mNotificationDataUri; private int mMessagesCount; @@ -316,6 +324,12 @@ public class PeopleSpaceTile implements Parcelable { return this; } + /** Sets the associated notification's sender. */ + public Builder setNotificationSender(CharSequence notificationSender) { + mNotificationSender = notificationSender; + return this; + } + /** Sets the associated notification's category. */ public Builder setNotificationCategory(String notificationCategory) { mNotificationCategory = notificationCategory; @@ -371,6 +385,7 @@ public class PeopleSpaceTile implements Parcelable { mIsImportantConversation = in.readBoolean(); mNotificationKey = in.readString(); mNotificationContent = in.readCharSequence(); + mNotificationSender = in.readCharSequence(); mNotificationCategory = in.readString(); mNotificationDataUri = in.readParcelable(Uri.class.getClassLoader()); mMessagesCount = in.readInt(); @@ -398,6 +413,7 @@ public class PeopleSpaceTile implements Parcelable { dest.writeBoolean(mIsImportantConversation); dest.writeString(mNotificationKey); dest.writeCharSequence(mNotificationContent); + dest.writeCharSequence(mNotificationSender); dest.writeString(mNotificationCategory); dest.writeParcelable(mNotificationDataUri, flags); dest.writeInt(mMessagesCount); diff --git a/core/java/android/app/search/Query.java b/core/java/android/app/search/Query.java index 3ab20bb30b22..34ace48148e6 100644 --- a/core/java/android/app/search/Query.java +++ b/core/java/android/app/search/Query.java @@ -16,63 +16,108 @@ package android.app.search; import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; /** + * Query object is sent over from client to the service. + * + * Inside the query object, there is a timestamp that trackes when the query string was typed. + * + * If this object was created for the {@link SearchSession#query}, + * the client expects first consumer to be returned + * within {@link #getTimestampMillis()} + {@link SearchContext#getTimeoutMillis()} + * Base of the timestamp should be SystemClock.elasedRealTime() + * * @hide */ @SystemApi public final class Query implements Parcelable { /** - * Query string typed from the client. + * string typed from the client. */ @NonNull private final String mInput; + private final long mTimestampMillis; + /** - * The timestamp that the query string was typed. If this object was created for the - * {@link SearchSession#query}, the client expects first consumer to be returned - * within mTimestamp + {@link SearchContext#mTimeoutMillis} + * Contains other client UI constraints related data */ - private final long mTimestamp; - - @Nullable + @NonNull private final Bundle mExtras; + /** + * Query object used to pass search box input from client to service. + * + * @param input string typed from the client + * @param timestampMillis timestamp that query string was typed. + * @param extras bundle that contains other client UI constraints data + */ public Query(@NonNull String input, - long timestamp, - @SuppressLint("NullableCollection") - @Nullable Bundle extras) { + long timestampMillis, + @NonNull Bundle extras) { mInput = input; - mTimestamp = timestamp; - mExtras = extras; + mTimestampMillis = timestampMillis; + mExtras = extras == null ? extras : new Bundle(); + } + + /** + * Query object used to pass search box input from client to service. + * + * @param input string typed from the client + * @param timestampMillis timestamp that query string was typed + */ + public Query(@NonNull String input, long timestampMillis) { + this(input, timestampMillis, new Bundle()); } private Query(Parcel parcel) { mInput = parcel.readString(); - mTimestamp = parcel.readLong(); + mTimestampMillis = parcel.readLong(); mExtras = parcel.readBundle(); } + /** + * @return string typed from the client + */ @NonNull public String getInput() { return mInput; } + /** + * @deprecated Will be replaced by {@link #getTimestampMillis()} as soon as + * new SDK is adopted. + * + * @removed + */ + @Deprecated @NonNull public long getTimestamp() { - return mTimestamp; + return mTimestampMillis; } - @Nullable - @SuppressLint("NullableCollection") + /** + * Base of the timestamp should be SystemClock.elasedRealTime() + * + * @return timestamp that query string was typed + */ + public long getTimestampMillis() { + return mTimestampMillis; + } + + /** + * @return bundle that contains other client constraints related to the query + */ + @NonNull public Bundle getExtras() { + if (mExtras == null) { + return new Bundle(); + } return mExtras; } @@ -84,7 +129,7 @@ public final class Query implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(mInput); - dest.writeLong(mTimestamp); + dest.writeLong(mTimestampMillis); dest.writeBundle(mExtras); } diff --git a/core/java/android/app/search/SearchContext.java b/core/java/android/app/search/SearchContext.java index 548b7daff3a6..3e345fa93d7b 100644 --- a/core/java/android/app/search/SearchContext.java +++ b/core/java/android/app/search/SearchContext.java @@ -17,13 +17,20 @@ package android.app.search; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + /** + * When {@link SearchSession} is created, {@link SearchContext} object is created + * to pass the result types from the {@link SearchSession#query(Query, Executor, Consumer)} + * method that the client wants. + * * @hide */ @SystemApi @@ -51,12 +58,25 @@ public final class SearchContext implements Parcelable { @Nullable private String mPackageName; + /** + * @param resultTypes {@link SearchTarget.SearchResultType}s combined using bit OR operation + * @param timeoutMillis timeout before client renders its own fallback result + */ + public SearchContext(int resultTypes, int timeoutMillis) { + this(resultTypes, timeoutMillis, new Bundle()); + } + + /** + * @param resultTypes {@link SearchTarget.SearchResultType}s combined using bit OR operation + * @param timeoutMillis timeout before client renders its own fallback result + * @param extras other client constraints (e.g., height of the search surface) + */ public SearchContext(int resultTypes, - int queryTimeoutMillis, - @SuppressLint("NullableCollection") @Nullable Bundle extras) { + int timeoutMillis, + @NonNull Bundle extras) { mResultTypes = resultTypes; - mTimeoutMillis = queryTimeoutMillis; - mExtras = extras; + mTimeoutMillis = timeoutMillis; + mExtras = Objects.requireNonNull(extras); } private SearchContext(Parcel parcel) { @@ -74,7 +94,7 @@ public final class SearchContext implements Parcelable { /** * @hide */ - public void setPackageName(@Nullable String packageName) { + void setPackageName(@Nullable String packageName) { mPackageName = packageName; } @@ -83,8 +103,7 @@ public final class SearchContext implements Parcelable { return mTimeoutMillis; } - @Nullable - @SuppressLint("NullableCollection") + @NonNull public Bundle getExtras() { return mExtras; } diff --git a/core/java/android/app/search/SearchSession.java b/core/java/android/app/search/SearchSession.java index 7bd88d9852fc..a5425a20655a 100644 --- a/core/java/android/app/search/SearchSession.java +++ b/core/java/android/app/search/SearchSession.java @@ -37,7 +37,9 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** - * Client API to share information about the search UI state and execute query. + * Client needs to create {@link SearchSession} object from in order to execute + * {@link #query(Query, Executor, Consumer)} method and share client side signals + * back to the service using {@link #notifyEvent(Query, SearchTargetEvent)}. * * <p> * Usage: <pre> {@code @@ -60,7 +62,7 @@ import java.util.function.Consumer; * } * * void onDestroy() { - * mSearchSession.destroy(); + * mSearchSession.close(); * } * * }</pre> @@ -108,7 +110,10 @@ public final class SearchSession implements AutoCloseable{ } /** - * Notifies the search service of an search target event. + * Notifies the search service of an search target event (e.g., user interaction + * and lifecycle event of the search surface). + * + * {@see SearchTargetEvent} * * @param query input object associated with the event. * @param event The {@link SearchTargetEvent} that represents the search target event. @@ -153,7 +158,11 @@ public final class SearchSession implements AutoCloseable{ /** * Destroys the client and unregisters the callback. Any method on this class after this call * will throw {@link IllegalStateException}. + * + * @deprecated + * @removed */ + @Deprecated public void destroy() { if (!mIsClosed.getAndSet(true)) { mCloseGuard.close(); @@ -188,6 +197,11 @@ public final class SearchSession implements AutoCloseable{ } } + /** + * Destroys the client and unregisters the callback. Any method on this class after this call + * will throw {@link IllegalStateException}. + * + */ @Override public void close() { try { diff --git a/core/java/android/app/search/SearchTarget.java b/core/java/android/app/search/SearchTarget.java index 6a80f8bd222a..56c5ddf9ace7 100644 --- a/core/java/android/app/search/SearchTarget.java +++ b/core/java/android/app/search/SearchTarget.java @@ -15,34 +15,73 @@ */ package android.app.search; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.annotation.SystemApi; +import android.app.slice.SliceManager; import android.appwidget.AppWidgetProviderInfo; +import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; import android.net.Uri; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** - * A representation of a searchable item info. + * A representation of a search result. Search result can be expressed in one of the following: + * app icon, shortcut, slice, widget, or a custom object using {@link SearchAction}. While + * app icon ({@link PackageManager}, shortcut {@link ShortcutManager}, slice {@link SliceManager}, + * or widget (@link AppWidgetManager} are published content backed by the system service, + * {@link SearchAction} is a custom object that the service can use to send search result to the + * client. + * + * These various types of Android primitives could be defined as {@link SearchResultType}. Some + * times, the result type can define the layout type that that this object can be rendered in. + * (e.g., app widget). Most times, {@link #getLayoutType()} assigned by the service + * can recommend which layout this target should be rendered in. + * + * The service can also use fields such as {@link #getScore()} to indicate + * how confidence the search result is and {@link #shouldHide()} to indicate + * whether it is recommended to be shown by default. + * + * Finally, {@link #getId()} is the unique identifier of this search target and a single + * search target is defined by being able to express a single launcheable item. In case the + * service want to recommend how to combine multiple search target objects to render in a group + * (e.g., same row), {@link #getParentId()} can be assigned on the sub targets of the group + * using the primary search target's identifier. * * @hide */ @SystemApi public final class SearchTarget implements Parcelable { - - @NonNull + public static final int RESULT_TYPE_APPLICATION = 1 << 0; + public static final int RESULT_TYPE_SHORTCUT = 1 << 1; + public static final int RESULT_TYPE_SLICE = 1 << 2; + public static final int RESULT_TYPE_WIDGETS = 1 << 3; + /** + * @hide + */ + @IntDef(prefix = {"RESULT_TYPE_"}, value = { + RESULT_TYPE_APPLICATION, + RESULT_TYPE_SHORTCUT, + RESULT_TYPE_SLICE, + RESULT_TYPE_WIDGETS + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SearchResultType {} private final int mResultType; /** - * Constant to express how the group of {@link SearchTarget} should be laid out. + * Constant to express how the group of {@link SearchTarget} should be rendered on + * the client side. (e.g., "icon", "icon_row", "short_icon_row") */ @NonNull private final String mLayoutType; @@ -69,13 +108,13 @@ public final class SearchTarget implements Parcelable { private final AppWidgetProviderInfo mAppWidgetProviderInfo; @Nullable private final Uri mSliceUri; - @Nullable + + @NonNull private final Bundle mExtras; private SearchTarget(Parcel parcel) { mResultType = parcel.readInt(); mLayoutType = parcel.readString(); - mId = parcel.readString(); mParentId = parcel.readString(); mScore = parcel.readFloat(); @@ -102,7 +141,7 @@ public final class SearchTarget implements Parcelable { @Nullable ShortcutInfo shortcutInfo, @Nullable Uri sliceUri, @Nullable AppWidgetProviderInfo appWidgetProviderInfo, - @Nullable Bundle extras) { + @NonNull Bundle extras) { mResultType = resultType; mLayoutType = Objects.requireNonNull(layoutType); mId = Objects.requireNonNull(id); @@ -129,9 +168,9 @@ public final class SearchTarget implements Parcelable { } /** - * Retrieves the result type. + * Retrieves the result type {@see SearchResultType}. */ - public int getResultType() { + public @SearchResultType int getResultType() { return mResultType; } @@ -167,7 +206,7 @@ public final class SearchTarget implements Parcelable { } /** - * TODO: add comment + * Indicates whether this object should be hidden and shown only on demand. */ public boolean shouldHide() { return mShouldHide; @@ -198,7 +237,7 @@ public final class SearchTarget implements Parcelable { } /** - * Return widget provider info. + * Return a widget provider info. */ @Nullable public AppWidgetProviderInfo getAppWidgetProviderInfo() { @@ -206,7 +245,7 @@ public final class SearchTarget implements Parcelable { } /** - * Return slice uri. + * Returns a slice uri. */ @Nullable public Uri getSliceUri() { @@ -214,7 +253,7 @@ public final class SearchTarget implements Parcelable { } /** - * Return search action. + * Returns a search action. */ @Nullable public SearchAction getSearchAction() { @@ -224,8 +263,7 @@ public final class SearchTarget implements Parcelable { /** * Return extra bundle. */ - @Nullable - @SuppressLint("NullableCollection") + @NonNull public Bundle getExtras() { return mExtras; } @@ -295,10 +333,10 @@ public final class SearchTarget implements Parcelable { private Uri mSliceUri; @Nullable private AppWidgetProviderInfo mAppWidgetProviderInfo; - @Nullable + @NonNull private Bundle mExtras; - public Builder(int resultType, + public Builder(@SearchResultType int resultType, @NonNull String layoutType, @NonNull String id) { mId = id; @@ -369,32 +407,30 @@ public final class SearchTarget implements Parcelable { */ @NonNull public Builder setSliceUri(@NonNull Uri sliceUri) { - // TODO: add packageName check mSliceUri = sliceUri; return this; } /** - * TODO: add comment + * Set the {@link SearchAction} object to this target. */ @NonNull - public Builder setSearchAction(@Nullable SearchAction remoteAction) { - // TODO: add packageName check - mSearchAction = remoteAction; + public Builder setSearchAction(@Nullable SearchAction searchAction) { + mSearchAction = searchAction; return this; } /** - * TODO: add comment + * Set any extra information that needs to be shared between service and the client. */ @NonNull - public Builder setExtras(@SuppressLint("NullableCollection") @Nullable Bundle extras) { - mExtras = extras; + public Builder setExtras(@NonNull Bundle extras) { + mExtras = Objects.requireNonNull(extras); return this; } /** - * TODO: add comment + * Sets the score of the object. */ @NonNull public Builder setScore(float score) { @@ -403,7 +439,7 @@ public final class SearchTarget implements Parcelable { } /** - * TODO: add comment + * Sets whether the result should be hidden by default inside client. */ @NonNull public Builder setShouldHide(boolean shouldHide) { diff --git a/core/java/android/app/search/SearchTargetEvent.java b/core/java/android/app/search/SearchTargetEvent.java index f478dc3c8fc7..d4915afd5ce6 100644 --- a/core/java/android/app/search/SearchTargetEvent.java +++ b/core/java/android/app/search/SearchTargetEvent.java @@ -29,7 +29,11 @@ import java.util.List; import java.util.Objects; /** - * A representation of an app target event. + * A representation of an search target event. + * + * There are two types of events. First type of event correspends to the user interaction + * that happens on the search surface. (e.g., {@link #ACTION_TAP}. Second type of events + * correspends to the lifecycle event of the search surface {@link #ACTION_SURFACE_VISIBLE}. * * @hide */ diff --git a/core/java/android/app/search/SearchUiManager.java b/core/java/android/app/search/SearchUiManager.java index 636bfe15df03..ce6d8b273821 100644 --- a/core/java/android/app/search/SearchUiManager.java +++ b/core/java/android/app/search/SearchUiManager.java @@ -25,6 +25,12 @@ import java.util.Objects; /** * Class that provides methods to create search ui session clients. * + * Usage: <pre> {@code + * mSearchUiManager = context.getSystemService(SearchUiManager.class); + * mSearchSession.createSearchSession(searchContext) + * + * }</pre> + * * @hide */ @SystemApi diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 8afc557ef85e..9fc1f88c01c8 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1311,11 +1311,15 @@ public final class BluetoothAdapter { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean factoryReset() { try { mServiceLock.readLock().lock(); - if (mService != null && mService.factoryReset() + if (mService != null && mService.factoryReset(mAttributionSource) && mManagerService != null && mManagerService.onFactoryReset(mAttributionSource)) { return true; @@ -1430,7 +1434,11 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setBluetoothClass(BluetoothClass bluetoothClass) { if (getState() != STATE_ON) { return false; @@ -1438,7 +1446,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.setBluetoothClass(bluetoothClass); + return mService.setBluetoothClass(bluetoothClass, mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1487,12 +1495,16 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setIoCapability(@IoCapability int capability) { if (getState() != STATE_ON) return false; try { mServiceLock.readLock().lock(); - if (mService != null) return mService.setIoCapability(capability); + if (mService != null) return mService.setIoCapability(capability, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.getMessage(), e); } finally { @@ -1540,12 +1552,16 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setLeIoCapability(@IoCapability int capability) { if (getState() != STATE_ON) return false; try { mServiceLock.readLock().lock(); - if (mService != null) return mService.setLeIoCapability(capability); + if (mService != null) return mService.setLeIoCapability(capability, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.getMessage(), e); } finally { @@ -1739,12 +1755,16 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public long getDiscoveryEndMillis() { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getDiscoveryEndMillis(); + return mService.getDiscoveryEndMillis(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2353,7 +2373,11 @@ public final class BluetoothAdapter { * instead. */ @Deprecated - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { SynchronousResultReceiver receiver = new SynchronousResultReceiver(); requestControllerActivityEnergyInfo(receiver); @@ -2379,12 +2403,16 @@ public final class BluetoothAdapter { * @param result The callback to which to send the activity info. * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public void requestControllerActivityEnergyInfo(ResultReceiver result) { try { mServiceLock.readLock().lock(); if (mService != null) { - mService.requestActivityInfo(result); + mService.requestActivityInfo(result, mAttributionSource); result = null; } } catch (RemoteException e) { @@ -3141,7 +3169,7 @@ public final class BluetoothAdapter { sMetadataListeners.forEach((device, pair) -> { try { mService.registerMetadataListener(sBluetoothMetadataListener, - device); + device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Failed to register metadata listener", e); } @@ -3150,7 +3178,8 @@ public final class BluetoothAdapter { synchronized (mBluetoothConnectionCallbackExecutorMap) { if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) { try { - mService.registerBluetoothConnectionCallback(mConnectionCallback); + mService.registerBluetoothConnectionCallback(mConnectionCallback, + mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "onBluetoothServiceUp: Failed to register bluetooth" + "connection callback", e); @@ -3276,7 +3305,7 @@ public final class BluetoothAdapter { * @param transport - whether the {@link OobData} is generated for LE or Classic. * @param oobData - data generated in the host stack(LE) or controller (Classic) */ - void onOobData(@Transport int transport, @Nullable OobData oobData); + void onOobData(@Transport int transport, @NonNull OobData oobData); /** * Provides feedback when things don't go as expected. @@ -3317,7 +3346,7 @@ public final class BluetoothAdapter { * * @hide */ - public void onOobData(@Transport int transport, OobData oobData) { + public void onOobData(@Transport int transport, @NonNull OobData oobData) { mExecutor.execute(new Runnable() { public void run() { mCallback.onOobData(transport, oobData); @@ -3364,7 +3393,11 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public void generateLocalOobData(@Transport int transport, @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback) { if (transport != BluetoothDevice.TRANSPORT_BREDR && transport @@ -3378,7 +3411,7 @@ public final class BluetoothAdapter { } else { try { mService.generateLocalOobData(transport, new WrappedOobDataCallback(callback, - executor)); + executor), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -3515,11 +3548,13 @@ public final class BluetoothAdapter { /** {@hide} */ @UnsupportedAppUsage + @RequiresNoPermission public IBluetoothManager getBluetoothManager() { return mManagerService; } /** {@hide} */ + @RequiresNoPermission public AttributionSource getAttributionSource() { return mAttributionSource; } @@ -3892,7 +3927,11 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device, @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) { if (DBG) Log.d(TAG, "addOnMetadataChangedListener()"); @@ -3932,7 +3971,8 @@ public final class BluetoothAdapter { boolean ret = false; try { - ret = service.registerMetadataListener(sBluetoothMetadataListener, device); + ret = service.registerMetadataListener(sBluetoothMetadataListener, device, + mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "registerMetadataListener fail", e); } finally { @@ -3965,7 +4005,11 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device, @NonNull OnMetadataChangedListener listener) { if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()"); @@ -3993,7 +4037,7 @@ public final class BluetoothAdapter { return true; } try { - return service.unregisterMetadataListener(device); + return service.unregisterMetadataListener(device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "unregisterMetadataListener fail", e); return false; @@ -4055,7 +4099,11 @@ public final class BluetoothAdapter { * @throws IllegalArgumentException if the callback is already registered * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean registerBluetoothConnectionCallback(@NonNull @CallbackExecutor Executor executor, @NonNull BluetoothConnectionCallback callback) { if (DBG) Log.d(TAG, "registerBluetoothConnectionCallback()"); @@ -4069,7 +4117,8 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - if (!mService.registerBluetoothConnectionCallback(mConnectionCallback)) { + if (!mService.registerBluetoothConnectionCallback(mConnectionCallback, + mAttributionSource)) { return false; } } @@ -4098,7 +4147,11 @@ public final class BluetoothAdapter { * @return true if the callback was unregistered successfully, false otherwise * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean unregisterBluetoothConnectionCallback( @NonNull BluetoothConnectionCallback callback) { if (DBG) Log.d(TAG, "unregisterBluetoothConnectionCallback()"); @@ -4120,7 +4173,8 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.unregisterBluetoothConnectionCallback(mConnectionCallback); + return mService.unregisterBluetoothConnectionCallback(mConnectionCallback, + mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 98823b096a55..0ca6d74c6759 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1644,7 +1644,10 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean canBondWithoutDialog() { final IBluetooth service = sService; if (service == null) { @@ -1653,7 +1656,7 @@ public final class BluetoothDevice implements Parcelable { } try { if (DBG) Log.d(TAG, "canBondWithoutDialog, device: " + this); - return service.canBondWithoutDialog(this); + return service.canBondWithoutDialog(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1874,7 +1877,10 @@ public final class BluetoothDevice implements Parcelable { * * @return true confirmation has been sent out false for error */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setPairingConfirmation(boolean confirm) { final IBluetooth service = sService; if (service == null) { @@ -1882,7 +1888,7 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.setPairingConfirmation(this, confirm); + return service.setPairingConfirmation(this, confirm, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1971,14 +1977,17 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setSilenceMode(boolean silence) { final IBluetooth service = sService; if (service == null) { throw new IllegalStateException("Bluetooth is not turned ON"); } try { - return service.setSilenceMode(this, silence); + return service.setSilenceMode(this, silence, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "setSilenceMode fail", e); return false; @@ -1993,14 +2002,17 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean isInSilenceMode() { final IBluetooth service = sService; if (service == null) { throw new IllegalStateException("Bluetooth is not turned ON"); } try { - return service.getSilenceMode(this); + return service.getSilenceMode(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "isInSilenceMode fail", e); return false; @@ -2016,14 +2028,17 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setPhonebookAccessPermission(@AccessPermission int value) { final IBluetooth service = sService; if (service == null) { return false; } try { - return service.setPhonebookAccessPermission(this, value); + return service.setPhonebookAccessPermission(this, value, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -2063,7 +2078,10 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setMessageAccessPermission(@AccessPermission int value) { // Validates param value is one of the accepted constants if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) { @@ -2074,7 +2092,7 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.setMessageAccessPermission(this, value); + return service.setMessageAccessPermission(this, value, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -2114,14 +2132,17 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setSimAccessPermission(int value) { final IBluetooth service = sService; if (service == null) { return false; } try { - return service.setSimAccessPermission(this, value); + return service.setSimAccessPermission(this, value, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -2616,7 +2637,10 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) { final IBluetooth service = sService; if (service == null) { @@ -2628,7 +2652,7 @@ public final class BluetoothDevice implements Parcelable { + ", should not over " + METADATA_MAX_LENGTH); } try { - return service.setMetadata(this, key, value); + return service.setMetadata(this, key, value, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "setMetadata fail", e); return false; @@ -2644,7 +2668,10 @@ public final class BluetoothDevice implements Parcelable { */ @SystemApi @Nullable - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public byte[] getMetadata(@MetadataKey int key) { final IBluetooth service = sService; if (service == null) { @@ -2652,7 +2679,7 @@ public final class BluetoothDevice implements Parcelable { return null; } try { - return service.getMetadata(this, key); + return service.getMetadata(this, key, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "getMetadata fail", e); return null; diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 9dc2d8e9539e..3bf517c046f3 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -31,6 +31,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -365,6 +366,15 @@ public final class BluetoothHeadset implements BluetoothProfile { mAdapter = adapter; mAttributionSource = adapter.getAttributionSource(); + // Preserve legacy compatibility where apps were depending on + // registerStateChangeCallback() performing a permissions check which + // has been relaxed in modern platform versions + if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R + && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Need BLUETOOTH permission"); + } + IBluetoothManager mgr = mAdapter.getBluetoothManager(); if (mgr != null) { try { diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java index 2600029362a3..8ce01a37cdde 100644 --- a/core/java/android/bluetooth/BluetoothPbap.java +++ b/core/java/android/bluetooth/BluetoothPbap.java @@ -30,6 +30,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.PackageManager; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; @@ -136,6 +137,16 @@ public class BluetoothPbap implements BluetoothProfile { mServiceListener = l; mAdapter = adapter; mAttributionSource = adapter.getAttributionSource(); + + // Preserve legacy compatibility where apps were depending on + // registerStateChangeCallback() performing a permissions check which + // has been relaxed in modern platform versions + if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R + && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Need BLUETOOTH permission"); + } + IBluetoothManager mgr = mAdapter.getBluetoothManager(); if (mgr != null) { try { diff --git a/core/java/android/bluetooth/BluetoothProfileConnector.java b/core/java/android/bluetooth/BluetoothProfileConnector.java index b20ab754932c..beff841f2fc5 100644 --- a/core/java/android/bluetooth/BluetoothProfileConnector.java +++ b/core/java/android/bluetooth/BluetoothProfileConnector.java @@ -21,6 +21,8 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; @@ -123,6 +125,16 @@ public abstract class BluetoothProfileConnector<T> { mContext = context; mServiceListener = listener; IBluetoothManager mgr = BluetoothAdapter.getDefaultAdapter().getBluetoothManager(); + + // Preserve legacy compatibility where apps were depending on + // registerStateChangeCallback() performing a permissions check which + // has been relaxed in modern platform versions + if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R + && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Need BLUETOOTH permission"); + } + if (mgr != null) { try { mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java index d6868e0ffd5c..2dfa91dcba3e 100644 --- a/core/java/android/bluetooth/OobData.java +++ b/core/java/android/bluetooth/OobData.java @@ -25,7 +25,6 @@ import android.os.Parcelable; import com.android.internal.util.Preconditions; -import java.lang.IllegalArgumentException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -165,68 +164,6 @@ public final class OobData implements Parcelable { public static final int LE_FLAG_SIMULTANEOUS_HOST = 0x04; /** - * Main creation method for creating a Classic version of {@link OobData}. - * - * <p>This object will allow the caller to call {@link ClassicBuilder#build()} - * to build the data object or add any option information to the builder. - * - * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} octets - * of data. Data is derived from controller/host stack and is required for pairing OOB. - * @param classicLength byte array representing the length of data from 8-65535 across 2 - * octets (0xXXXX). - * @param deviceAddressWithType byte array representing the Bluetooth Address of the device - * that owns the OOB data. (i.e. the originator) [6 octets] - * - * @return a Classic Builder instance with all the given data set or null. - * - * @throws IllegalArgumentException if any of the values fail to be set. - * @throws NullPointerException if any argument is null. - * - * @hide - */ - @NonNull - @SystemApi - public static ClassicBuilder createClassicBuilder(@NonNull byte[] confirmationHash, - @NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType) { - return new ClassicBuilder(confirmationHash, classicLength, deviceAddressWithType); - } - - /** - * Main creation method for creating a LE version of {@link OobData}. - * - * <p>This object will allow the caller to call {@link LeBuilder#build()} - * to build the data object or add any option information to the builder. - * - * @param deviceAddressWithType the LE device address plus the address type (7 octets); - * not null. - * @param leDeviceRole whether the device supports Peripheral, Central, - * Both including preference; not null. (1 octet) - * @param confirmationHash Array consisting of {@link OobData#CONFIRMATION_OCTETS} octets - * of data. Data is derived from controller/host stack and is - * required for pairing OOB. - * - * <p>Possible LE Device Role Values: - * 0x00 Only Peripheral supported - * 0x01 Only Central supported - * 0x02 Central & Peripheral supported; Peripheral Preferred - * 0x03 Only peripheral supported; Central Preferred - * 0x04 - 0xFF Reserved - * - * @return a LeBuilder instance with all the given data set or null. - * - * @throws IllegalArgumentException if any of the values fail to be set. - * @throws NullPointerException if any argument is null. - * - * @hide - */ - @NonNull - @SystemApi - public static LeBuilder createLeBuilder(@NonNull byte[] confirmationHash, - @NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole) { - return new LeBuilder(confirmationHash, deviceAddressWithType, leDeviceRole); - } - - /** * Builds an {@link OobData} object and validates that the required combination * of values are present to create the LE specific OobData type. * @@ -342,16 +279,18 @@ public final class OobData implements Parcelable { private @LeFlag int mLeFlags = LE_FLAG_GENERAL_DISCOVERY_MODE; // Invalid default /** - * Constructing an OobData object for use with LE requires - * a LE Device Address and LE Device Role as well as the Confirmation - * and optionally, the Randomizer, however it is recommended to use. + * Main creation method for creating a LE version of {@link OobData}. * - * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} - * octets of data. Data is derived from controller/host stack and is required for - * pairing OOB. - * @param deviceAddressWithType 7 bytes containing the 6 byte address with the 1 byte - * address type. - * @param leDeviceRole indicating device's role and preferences (Central or Peripheral) + * <p>This object will allow the caller to call {@link LeBuilder#build()} + * to build the data object or add any option information to the builder. + * + * @param deviceAddressWithType the LE device address plus the address type (7 octets); + * not null. + * @param leDeviceRole whether the device supports Peripheral, Central, + * Both including preference; not null. (1 octet) + * @param confirmationHash Array consisting of {@link OobData#CONFIRMATION_OCTETS} octets + * of data. Data is derived from controller/host stack and is + * required for pairing OOB. * * <p>Possible Values: * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported @@ -361,11 +300,13 @@ public final class OobData implements Parcelable { * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred * 0x04 - 0xFF Reserved * - * @throws IllegalArgumentException if deviceAddressWithType is not - * {@link LE_DEVICE_ADDRESS_OCTETS} octets + * @throws IllegalArgumentException if any of the values fail to be set. * @throws NullPointerException if any argument is null. + * + * @hide */ - private LeBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] deviceAddressWithType, + @SystemApi + public LeBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole) { Preconditions.checkNotNull(confirmationHash); Preconditions.checkNotNull(deviceAddressWithType); @@ -572,25 +513,26 @@ public final class OobData implements Parcelable { private byte[] mClassOfDevice = null; /** + * Main creation method for creating a Classic version of {@link OobData}. + * + * <p>This object will allow the caller to call {@link ClassicBuilder#build()} + * to build the data object or add any option information to the builder. + * * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} * octets of data. Data is derived from controller/host stack and is required for pairing * OOB. - * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets - * of data. Data is derived from controller/host stack and is required - * for pairing OOB. Also, randomizerHash may be all 0s or null in which case - * it becomes all 0s. * @param classicLength byte array representing the length of data from 8-65535 across 2 - * octets (0xXXXX). Inclusive of this value in the length. + * octets (0xXXXX). * @param deviceAddressWithType byte array representing the Bluetooth Address of the device - * that owns the OOB data. (i.e. the originator) [7 octets] this includes the Address Type - * as the last octet. + * that owns the OOB data. (i.e. the originator) [6 octets] * - * @throws IllegalArgumentException if any value is not the correct length - * @throws NullPointerException if anything passed is null + * @throws IllegalArgumentException if any of the values fail to be set. + * @throws NullPointerException if any argument is null. * * @hide */ - private ClassicBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] classicLength, + @SystemApi + public ClassicBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType) { Preconditions.checkNotNull(confirmationHash); Preconditions.checkNotNull(classicLength); diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java index caa91fb23918..bbdb6953afd1 100644 --- a/core/java/android/bluetooth/le/AdvertisingSet.java +++ b/core/java/android/bluetooth/le/AdvertisingSet.java @@ -205,10 +205,14 @@ public final class AdvertisingSet { * * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothAdvertisePermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_ADVERTISE, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public void getOwnAddress() { try { - mGatt.getOwnAddress(mAdvertiserId); + mGatt.getOwnAddress(mAdvertiserId, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "remote exception - ", e); } diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 7e1df1b0e59c..114ad874d0c4 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -1885,9 +1885,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall * in {@link android.provider.MediaStore.MediaColumns}.</p> * * @param uri The URI whose file is to be opened. - * @param mode Access mode for the file. May be "r" for read-only access, - * "rw" for read and write access, or "rwt" for read and write access - * that truncates any existing file. + * @param mode The string representation of the file mode. Can be "r", "w", + * "wt", "wa", "rw" or "rwt". See + * {@link ParcelFileDescriptor#parseMode} for more details. * * @return Returns a new ParcelFileDescriptor which you can use to access * the file. @@ -1948,10 +1948,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall * in {@link android.provider.MediaStore.MediaColumns}.</p> * * @param uri The URI whose file is to be opened. - * @param mode Access mode for the file. May be "r" for read-only access, - * "w" for write-only access, "rw" for read and write access, or - * "rwt" for read and write access that truncates any existing - * file. + * @param mode The string representation of the file mode. Can be "r", "w", + * "wt", "wa", "rw" or "rwt". See + * {@link ParcelFileDescriptor#parseMode} for more details. * @param signal A signal to cancel the operation in progress, or * {@code null} if none. For example, if you are downloading a * file from the network to service a "rw" mode request, you @@ -2011,11 +2010,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p> * * @param uri The URI whose file is to be opened. - * @param mode Access mode for the file. May be "r" for read-only access, - * "w" for write-only access (erasing whatever data is currently in - * the file), "wa" for write-only access to append to any existing data, - * "rw" for read and write access on any existing data, and "rwt" for read - * and write access that truncates any existing file. + * @param mode The string representation of the file mode. Can be "r", "w", + * "wt", "wa", "rw" or "rwt". See + * {@link ParcelFileDescriptor#parseMode} for more details. * * @return Returns a new AssetFileDescriptor which you can use to access * the file. @@ -2068,11 +2065,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p> * * @param uri The URI whose file is to be opened. - * @param mode Access mode for the file. May be "r" for read-only access, - * "w" for write-only access (erasing whatever data is currently in - * the file), "wa" for write-only access to append to any existing data, - * "rw" for read and write access on any existing data, and "rwt" for read - * and write access that truncates any existing file. + * @param mode The string representation of the file mode. Can be "r", "w", + * "wt", "wa", "rw" or "rwt". See + * {@link ParcelFileDescriptor#parseMode} for more details. * @param signal A signal to cancel the operation in progress, or * {@code null} if none. For example, if you are downloading a * file from the network to service a "rw" mode request, you @@ -2103,11 +2098,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall * by looking up a column named "_data" at the given URI. * * @param uri The URI to be opened. - * @param mode The file mode. May be "r" for read-only access, - * "w" for write-only access (erasing whatever data is currently in - * the file), "wa" for write-only access to append to any existing data, - * "rw" for read and write access on any existing data, and "rwt" for read - * and write access that truncates any existing file. + * @param mode The string representation of the file mode. Can be "r", "w", + * "wt", "wa", "rw" or "rwt". See + * {@link ParcelFileDescriptor#parseMode} for more details. * * @return Returns a new ParcelFileDescriptor that can be used by the * client to access the file. diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index aec39da973f0..1132991a57f8 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -63,7 +63,9 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; +import android.system.ErrnoException; import android.system.Int64Ref; +import android.system.Os; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; @@ -76,8 +78,10 @@ import com.android.internal.util.MimeIconUtils; import dalvik.system.CloseGuard; import java.io.File; +import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -864,6 +868,20 @@ public abstract class ContentResolver implements ContentInterface { return wrap((ContentInterface) wrapped); } + /** + * Offer to locally truncate the given file when opened using the write-only + * mode. This is typically used to preserve legacy compatibility behavior. + */ + private static void maybeTruncate(FileDescriptor fd, String mode) throws FileNotFoundException { + if ("w".equals(mode)) { + try { + Os.ftruncate(fd, 0); + } catch (ErrnoException e) { + throw new FileNotFoundException("Failed to truncate: " + e.getMessage()); + } + } + } + /** @hide */ @SuppressWarnings("HiddenAbstractMethod") @UnsupportedAppUsage @@ -1525,8 +1543,20 @@ public abstract class ContentResolver implements ContentInterface { } /** - * Synonym for {@link #openOutputStream(Uri, String) - * openOutputStream(uri, "w")}. + * Open a stream on to the content associated with a content URI. If there + * is no data associated with the URI, FileNotFoundException is thrown. + * + * <h5>Accepts the following URI schemes:</h5> + * <ul> + * <li>content ({@link #SCHEME_CONTENT})</li> + * <li>file ({@link #SCHEME_FILE})</li> + * </ul> + * + * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information + * on these schemes. + * + * <p>This method behaves like {@link FileOutputStream} and automatically + * truncates any existing contents. * * @param uri The desired URI. * @return an OutputStream or {@code null} if the provider recently crashed. @@ -1534,7 +1564,16 @@ public abstract class ContentResolver implements ContentInterface { */ public final @Nullable OutputStream openOutputStream(@NonNull Uri uri) throws FileNotFoundException { - return openOutputStream(uri, "w"); + AssetFileDescriptor fd = openAssetFileDescriptor(uri, "w", null); + if (fd == null) return null; + try { + final FileOutputStream res = fd.createOutputStream(); + // Unconditionally truncate to mirror FileOutputStream behavior + maybeTruncate(res.getFD(), "w"); + return res; + } catch (IOException e) { + throw new FileNotFoundException("Unable to create stream"); + } } /** @@ -1551,7 +1590,9 @@ public abstract class ContentResolver implements ContentInterface { * on these schemes. * * @param uri The desired URI. - * @param mode May be "w", "wa", "rw", or "rwt". + * @param mode The string representation of the file mode. Can be "r", "w", + * "wt", "wa", "rw" or "rwt". See + * {@link ParcelFileDescriptor#parseMode} for more details. * @return an OutputStream or {@code null} if the provider recently crashed. * @throws FileNotFoundException if the provided URI could not be opened. * @see #openAssetFileDescriptor(Uri, String) @@ -1559,8 +1600,14 @@ public abstract class ContentResolver implements ContentInterface { public final @Nullable OutputStream openOutputStream(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null); + if (fd == null) return null; try { - return fd != null ? fd.createOutputStream() : null; + final FileOutputStream res = fd.createOutputStream(); + // Preserve legacy behavior by offering to truncate + if (mTargetSdkVersion < Build.VERSION_CODES.Q) { + maybeTruncate(res.getFD(), mode); + } + return res; } catch (IOException e) { throw new FileNotFoundException("Unable to create stream"); } @@ -1607,8 +1654,9 @@ public abstract class ContentResolver implements ContentInterface { * provider, use {@link ParcelFileDescriptor#closeWithError(String)}. * * @param uri The desired URI to open. - * @param mode The file mode to use, as per {@link ContentProvider#openFile - * ContentProvider.openFile}. + * @param mode The string representation of the file mode. Can be "r", "w", + * "wt", "wa", "rw" or "rwt". See + * {@link ParcelFileDescriptor#parseMode} for more details. * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the * provider recently crashed. You own this descriptor and are responsible for closing it * when done. @@ -1650,8 +1698,9 @@ public abstract class ContentResolver implements ContentInterface { * provider, use {@link ParcelFileDescriptor#closeWithError(String)}. * * @param uri The desired URI to open. - * @param mode The file mode to use, as per {@link ContentProvider#openFile - * ContentProvider.openFile}. + * @param mode The string representation of the file mode. Can be "r", "w", + * "wt", "wa", "rw" or "rwt". See + * {@link ParcelFileDescriptor#parseMode} for more details. * @param cancellationSignal A signal to cancel the operation in progress, * or null if none. If the operation is canceled, then * {@link OperationCanceledException} will be thrown. @@ -1744,8 +1793,9 @@ public abstract class ContentResolver implements ContentInterface { * from any built-in data conversion that a provider implements. * * @param uri The desired URI to open. - * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile - * ContentProvider.openAssetFile}. + * @param mode The string representation of the file mode. Can be "r", "w", + * "wt", "wa", "rw" or "rwt". See + * {@link ParcelFileDescriptor#parseMode} for more details. * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the * provider recently crashed. You own this descriptor and are responsible for closing it * when done. @@ -1798,8 +1848,9 @@ public abstract class ContentResolver implements ContentInterface { * from any built-in data conversion that a provider implements. * * @param uri The desired URI to open. - * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile - * ContentProvider.openAssetFile}. + * @param mode The string representation of the file mode. Can be "r", "w", + * "wt", "wa", "rw" or "rwt". See + * {@link ParcelFileDescriptor#parseMode} for more details. * @param cancellationSignal A signal to cancel the operation in progress, or null if * none. If the operation is canceled, then * {@link OperationCanceledException} will be thrown. @@ -1835,6 +1886,10 @@ public abstract class ContentResolver implements ContentInterface { } else if (SCHEME_FILE.equals(scheme)) { ParcelFileDescriptor pfd = ParcelFileDescriptor.open( new File(uri.getPath()), ParcelFileDescriptor.parseMode(mode)); + // Preserve legacy behavior by offering to truncate + if (mTargetSdkVersion < Build.VERSION_CODES.Q) { + maybeTruncate(pfd.getFileDescriptor(), mode); + } return new AssetFileDescriptor(pfd, 0, -1); } else { if ("r".equals(mode)) { @@ -1892,6 +1947,11 @@ public abstract class ContentResolver implements ContentInterface { // ParcelFileDescriptorInner do that when it is closed. stableProvider = null; + // Preserve legacy behavior by offering to truncate + if (mTargetSdkVersion < Build.VERSION_CODES.Q) { + maybeTruncate(pfd.getFileDescriptor(), mode); + } + return new AssetFileDescriptor(pfd, fd.getStartOffset(), fd.getDeclaredLength()); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 39933a9ee7b4..7c7cfdb35162 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2189,6 +2189,8 @@ public class Intent implements Parcelable, Cloneable { * Type: String * </p> * + * E.g. {@link android.Manifest.permission_group.CONTACTS} + * * @hide */ @SystemApi @@ -5339,6 +5341,8 @@ public class Intent implements Parcelable, Cloneable { * A String[] holding attribution tags when used with * {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD} * + * E.g. an attribution tag could be location_provider, com.google.android.gms.*, etc. + * * @hide */ @SystemApi @@ -6393,7 +6397,9 @@ public class Intent implements Parcelable, Cloneable { public static final int FLAG_ACTIVITY_NO_HISTORY = 0x40000000; /** * If set, the activity will not be launched if it is already running - * at the top of the history stack. + * at the top of the history stack. See + * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html#TaskLaunchModes"> + * Tasks and Back Stack</a> for more information. */ public static final int FLAG_ACTIVITY_SINGLE_TOP = 0x20000000; /** @@ -6533,8 +6539,7 @@ public class Intent implements Parcelable, Cloneable { public static final int FLAG_ACTIVITY_RESET_TASK_IF_NEEDED = 0x00200000; /** * This flag is not normally set by application code, but set for you by - * the system if this activity is being launched from history - * (longpress home key). + * the system if this activity is being launched from history. */ public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 0x00100000; /** @@ -6567,7 +6572,9 @@ public class Intent implements Parcelable, Cloneable { * equivalent of the Activity manifest specifying {@link * android.R.attr#documentLaunchMode}="intoExisting". When used with * FLAG_ACTIVITY_MULTIPLE_TASK it is the equivalent of the Activity manifest specifying - * {@link android.R.attr#documentLaunchMode}="always". + * {@link android.R.attr#documentLaunchMode}="always". The flag is ignored even in + * conjunction with {@link #FLAG_ACTIVITY_MULTIPLE_TASK} when the Activity manifest specifies + * {@link android.R.attr#documentLaunchMode}="never". * * Refer to {@link android.R.attr#documentLaunchMode} for more information. * diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 7fe2a41cc4b9..5e72325eed43 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -796,6 +796,10 @@ interface IPackageManager { void setMimeGroup(String packageName, String group, in List<String> mimeTypes); + String getSplashScreenTheme(String packageName, int userId); + + void setSplashScreenTheme(String packageName, String themeName, int userId); + List<String> getMimeGroup(String packageName, String group); boolean isAutoRevokeWhitelisted(String packageName); diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS index f0def80505ce..4e674f6ec9a8 100644 --- a/core/java/android/content/pm/OWNERS +++ b/core/java/android/content/pm/OWNERS @@ -4,7 +4,8 @@ toddke@android.com toddke@google.com patb@google.com -per-file PackageParser.java = chiuwinson@google.com +per-file PackageParser.java = set noparent +per-file PackageParser.java = chiuwinson@google.com,patb@google.com,toddke@google.com per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS per-file AppSearchPerson.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 90105d394244..99bbcdea06fc 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3969,6 +3969,7 @@ public abstract class PackageManager { * @hide */ @TestApi + @SystemApi public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 1 << 7; /** diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 86a8a9d69782..4ff26242dab2 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -214,7 +214,6 @@ public class PackageParser { public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes"; public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY = "android.activity_window_layout_affinity"; - public static final String METADATA_ACTIVITY_LAUNCH_MODE = "android.activity.launch_mode"; /** * Bit mask of all the valid bits that can be set in recreateOnConfigChanges. diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index 55a6ab708da5..84317b3739c5 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -81,6 +81,7 @@ public class PackageUserState { public int installReason; public @PackageManager.UninstallReason int uninstallReason; public String harmfulAppWarning; + public String splashScreenTheme; public ArraySet<String> disabledComponents; public ArraySet<String> enabledComponents; @@ -130,6 +131,7 @@ public class PackageUserState { if (o.componentLabelIconOverrideMap != null) { this.componentLabelIconOverrideMap = new ArrayMap<>(o.componentLabelIconOverrideMap); } + splashScreenTheme = o.splashScreenTheme; } @Nullable @@ -242,6 +244,7 @@ public class PackageUserState { return componentLabelIconOverrideMap.get(componentName); } + /** * Test if this package is installed. */ @@ -479,7 +482,11 @@ public class PackageUserState { } if (harmfulAppWarning == null && oldState.harmfulAppWarning != null || (harmfulAppWarning != null - && !harmfulAppWarning.equals(oldState.harmfulAppWarning))) { + && !harmfulAppWarning.equals(oldState.harmfulAppWarning))) { + return false; + } + + if (!Objects.equals(splashScreenTheme, oldState.splashScreenTheme)) { return false; } return true; @@ -505,6 +512,7 @@ public class PackageUserState { hashCode = 31 * hashCode + Objects.hashCode(disabledComponents); hashCode = 31 * hashCode + Objects.hashCode(enabledComponents); hashCode = 31 * hashCode + Objects.hashCode(harmfulAppWarning); + hashCode = 31 * hashCode + Objects.hashCode(splashScreenTheme); return hashCode; } diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index 0fc6b2bd4f2e..e3aca970430f 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -183,6 +183,7 @@ public class ParsingPackageUtils { public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes"; public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY = "android.activity_window_layout_affinity"; + public static final String METADATA_ACTIVITY_LAUNCH_MODE = "android.activity.launch_mode"; public static final int SDK_VERSION = Build.VERSION.SDK_INT; public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES; diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java index ff6aaad09d09..aa740bdbc406 100644 --- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java @@ -24,7 +24,6 @@ import android.annotation.NonNull; import android.app.ActivityTaskManager; import android.content.Intent; import android.content.pm.ActivityInfo; -import android.content.pm.PackageParser; import android.content.pm.parsing.ParsingPackage; import android.content.pm.parsing.ParsingPackageUtils; import android.content.pm.parsing.ParsingUtils; @@ -414,9 +413,9 @@ public class ParsedActivityUtils { if (!isAlias && activity.launchMode != LAUNCH_SINGLE_INSTANCE_PER_TASK && activity.metaData != null && activity.metaData.containsKey( - PackageParser.METADATA_ACTIVITY_LAUNCH_MODE)) { + ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE)) { final String launchMode = activity.metaData.getString( - PackageParser.METADATA_ACTIVITY_LAUNCH_MODE); + ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE); if (launchMode != null && launchMode.equals("singleInstancePerTask")) { activity.launchMode = LAUNCH_SINGLE_INSTANCE_PER_TASK; } diff --git a/core/java/android/database/sqlite/package.html b/core/java/android/database/sqlite/package.html index 4d6ba28962d2..6ececa2e1416 100644 --- a/core/java/android/database/sqlite/package.html +++ b/core/java/android/database/sqlite/package.html @@ -20,6 +20,9 @@ with adb shell, for example, <code>adb -e shell sqlite3</code>. <p>The version of SQLite depends on the version of Android. See the following table: <table style="width:auto;"> <tr><th>Android API</th><th>SQLite Version</th></tr> + <tr><td>API 31</td><td>3.32</td></tr> + <tr><td>API 30</td><td>3.28</td></tr> + <tr><td>API 28</td><td>3.22</td></tr> <tr><td>API 27</td><td>3.19</td></tr> <tr><td>API 26</td><td>3.18</td></tr> <tr><td>API 24</td><td>3.9</td></tr> diff --git a/core/java/android/hardware/Battery.java b/core/java/android/hardware/BatteryState.java index 24c8d76a9813..aa7535982452 100644 --- a/core/java/android/hardware/Battery.java +++ b/core/java/android/hardware/BatteryState.java @@ -24,9 +24,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * The Battery class is a representation of a single battery on a device. + * The BatteryState class is a representation of a single battery on a device. */ -public abstract class Battery { +public abstract class BatteryState { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "STATUS_" }, value = { @@ -55,7 +55,7 @@ public abstract class Battery { * * @return True if the hardware has a battery, else false. */ - public abstract boolean hasBattery(); + public abstract boolean isPresent(); /** * Get the battery status. @@ -66,7 +66,7 @@ public abstract class Battery { /** * Get remaining battery capacity as float percentage [0.0f, 1.0f] of total capacity - * Returns -1 when battery capacity can't be read. + * Returns NaN when battery capacity can't be read. * * @return the battery capacity. */ diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java index d054ee207110..f3a83422469c 100644 --- a/core/java/android/hardware/biometrics/BiometricManager.java +++ b/core/java/android/hardware/biometrics/BiometricManager.java @@ -33,6 +33,8 @@ import android.annotation.TestApi; import android.content.Context; import android.os.IBinder; import android.os.RemoteException; +import android.os.UserHandle; +import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.util.Slog; @@ -556,9 +558,22 @@ public class BiometricManager { * @hide */ public long[] getAuthenticatorIds() { + return getAuthenticatorIds(UserHandle.myUserId()); + } + + /** + * Get a list of AuthenticatorIDs for biometric authenticators which have 1) enrolled templates, + * and 2) meet the requirements for integrating with Keystore. The AuthenticatorIDs are known + * in Keystore land as SIDs, and are used during key generation. + * + * @param userId Android user ID for user to look up. + * + * @hide + */ + public long[] getAuthenticatorIds(int userId) { if (mService != null) { try { - return mService.getAuthenticatorIds(); + return mService.getAuthenticatorIds(userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl index 86df0994a222..4c2a9ae10cbd 100644 --- a/core/java/android/hardware/biometrics/IAuthService.aidl +++ b/core/java/android/hardware/biometrics/IAuthService.aidl @@ -67,7 +67,9 @@ interface IAuthService { // Get a list of AuthenticatorIDs for authenticators which have enrolled templates and meet // the requirements for integrating with Keystore. The AuthenticatorID are known in Keystore // land as SIDs, and are used during key generation. - long[] getAuthenticatorIds(); + // If userId is not equal to the calling user ID, the caller must have the + // USE_BIOMETRIC_INTERNAL permission. + long[] getAuthenticatorIds(in int userId); // See documentation in BiometricManager. void resetLockoutTimeBound(IBinder token, String opPackageName, int fromSensorId, int userId, diff --git a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java index 17b2abf9f5d1..f365ee6066d0 100644 --- a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java +++ b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java @@ -44,7 +44,7 @@ public class SensorPropertiesInternal implements Parcelable { prop.resetLockoutRequiresHardwareAuthToken, prop.resetLockoutRequiresChallenge); } - protected SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength, + public SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength, int maxEnrollmentsPerUser, @NonNull List<ComponentInfoInternal> componentInfo, boolean resetLockoutRequiresHardwareAuthToken, boolean resetLockoutRequiresChallenge) { this.sensorId = sensorId; diff --git a/core/java/android/hardware/camera2/CameraInjectionSession.java b/core/java/android/hardware/camera2/CameraInjectionSession.java new file mode 100644 index 000000000000..bd5a4bcd77d7 --- /dev/null +++ b/core/java/android/hardware/camera2/CameraInjectionSession.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 android.hardware.camera2; + +import android.annotation.IntDef; +import android.annotation.NonNull; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * <p>The CameraInjectionSession class is what determines when injection is active.</p> + * + * <p>Your application must declare the + * {@link android.Manifest.permission#CAMERA_INJECT_EXTERNAL_CAMERA CAMERA} permission in its + * manifest in order to use camera injection function.</p> + * + * @hide + * @see CameraManager#injectCamera + * @see android.Manifest.permission#CAMERA_INJECT_EXTERNAL_CAMERA + */ +public abstract class CameraInjectionSession implements AutoCloseable { + + /** + * Close the external camera and switch back to the internal camera. + * + * <p>Call the method when app streaming stops or the app exits, it switch back to the internal + * camera.</p> + */ + @Override + public abstract void close(); + + /** + * A callback for external camera has a success or an error during injecting. + * + * <p>A callback instance must be provided to the {@link CameraManager#injectCamera} method to + * inject camera.</p> + * + * @hide + * @see CameraManager#injectCamera + */ + public abstract static class InjectionStatusCallback { + + /** + * An error code that can be reported by {@link #onInjectionError} indicating that the + * camera injection session has encountered a fatal error. + * + * @see #onInjectionError + */ + public static final int ERROR_INJECTION_SESSION = 0; + + /** + * An error code that can be reported by {@link #onInjectionError} indicating that the + * camera service has encountered a fatal error. + * + * <p>The Android device may need to be shut down and restarted to restore + * camera function, or there may be a persistent hardware problem.</p> + * + * <p>An attempt at recovery <i>may</i> be possible by closing the + * CameraDevice and the CameraManager, and trying to acquire all resources again from + * scratch.</p> + * + * @see #onInjectionError + */ + public static final int ERROR_INJECTION_SERVICE = 1; + + /** + * An error code that can be reported by {@link #onInjectionError} indicating that the + * injection camera does not support certain camera functions. When this error occurs, the + * default processing is still in the inject state, and the app is notified to display an + * error message and a black screen. + * + * @see #onInjectionError + */ + public static final int ERROR_INJECTION_UNSUPPORTED = 2; + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"ERROR_"}, value = + {ERROR_INJECTION_SESSION, + ERROR_INJECTION_SERVICE, + ERROR_INJECTION_UNSUPPORTED}) + public @interface ErrorCode {}; + + /** + * The method will be called when an external camera has been injected and replaced + * internal camera's feed. + * + * @param injectionSession The camera injection session that has been injected. + */ + public abstract void onInjectionSucceeded( + @NonNull CameraInjectionSession injectionSession); + + /** + * The method will be called when an error occurs in the injected external camera. + * + * @param errorCode The error code. + * @see #ERROR_INJECTION_SESSION + * @see #ERROR_INJECTION_SERVICE + * @see #ERROR_INJECTION_UNSUPPORTED + */ + public abstract void onInjectionError(@NonNull int errorCode); + } + + /** + * To be inherited by android.hardware.camera2.* code only. + * + * @hide + */ + public CameraInjectionSession() { + } +} diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 651f02591b4d..2c5ec25ee62d 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -28,6 +28,7 @@ import android.hardware.CameraStatus; import android.hardware.ICameraService; import android.hardware.ICameraServiceListener; import android.hardware.camera2.impl.CameraDeviceImpl; +import android.hardware.camera2.impl.CameraInjectionSessionImpl; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.params.ExtensionSessionConfiguration; import android.hardware.camera2.params.SessionConfiguration; @@ -1119,6 +1120,67 @@ public final class CameraManager { } /** + * Inject the external camera to replace the internal camera session. + * + * <p>If injecting the external camera device fails, then the injection callback's + * {@link CameraInjectionSession.InjectionStatusCallback#onInjectionError + * onInjectionError} method will be called.</p> + * + * @param packageName It scopes the injection to a particular app. + * @param internalCamId The id of one of the physical or logical cameras on the phone. + * @param externalCamId The id of one of the remote cameras that are provided by the dynamic + * camera HAL. + * @param executor The executor which will be used when invoking the callback. + * @param callback The callback which is invoked once the external camera is injected. + * + * @throws CameraAccessException If the camera device has been disconnected. + * {@link CameraAccessException#CAMERA_DISCONNECTED} will be + * thrown if camera service is not available. + * @throws SecurityException If the specific application that can cast to external + * devices does not have permission to inject the external + * camera. + * @throws IllegalArgumentException If cameraId doesn't match any currently or previously + * available camera device or some camera functions might not + * work properly or the injection camera runs into a fatal + * error. + * @hide + */ + @RequiresPermission(android.Manifest.permission.CAMERA_INJECT_EXTERNAL_CAMERA) + public void injectCamera(@NonNull String packageName, @NonNull String internalCamId, + @NonNull String externalCamId, @NonNull @CallbackExecutor Executor executor, + @NonNull CameraInjectionSession.InjectionStatusCallback callback) + throws CameraAccessException, SecurityException, + IllegalArgumentException { + if (CameraManagerGlobal.sCameraServiceDisabled) { + throw new IllegalArgumentException("No cameras available on device"); + } + ICameraService cameraService = CameraManagerGlobal.get().getCameraService(); + if (cameraService == null) { + throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED, + "Camera service is currently unavailable"); + } + synchronized (mLock) { + try { + CameraInjectionSessionImpl injectionSessionImpl = + new CameraInjectionSessionImpl(callback, executor); + ICameraInjectionCallback cameraInjectionCallback = + injectionSessionImpl.getCallback(); + ICameraInjectionSession injectionSession = cameraService.injectCamera(packageName, + internalCamId, externalCamId, cameraInjectionCallback); + injectionSessionImpl.setRemoteInjectionSession(injectionSession); + } catch (ServiceSpecificException e) { + throwAsPublicException(e); + } catch (RemoteException e) { + // Camera service died - act as if it's a CAMERA_DISCONNECTED case + ServiceSpecificException sse = new ServiceSpecificException( + ICameraService.ERROR_DISCONNECTED, + "Camera service is currently unavailable"); + throwAsPublicException(sse); + } + } + } + + /** * A per-process global camera manager instance, to retain a connection to the camera service, * and to distribute camera availability notices to API-registered callbacks */ diff --git a/core/java/android/hardware/camera2/impl/CameraInjectionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraInjectionSessionImpl.java new file mode 100644 index 000000000000..231cc05ad7cf --- /dev/null +++ b/core/java/android/hardware/camera2/impl/CameraInjectionSessionImpl.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.hardware.camera2.impl; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable; + +import android.hardware.camera2.CameraInjectionSession; +import android.hardware.camera2.ICameraInjectionCallback; +import android.hardware.camera2.ICameraInjectionSession; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.concurrent.Executor; + + +/** + * The class inherits CameraInjectionSession. Use CameraManager#injectCamera to instantiate. + */ +public class CameraInjectionSessionImpl extends CameraInjectionSession + implements IBinder.DeathRecipient { + private static final String TAG = "CameraInjectionSessionImpl"; + + private final CameraInjectionCallback mCallback = new CameraInjectionCallback(); + private final CameraInjectionSession.InjectionStatusCallback mInjectionStatusCallback; + private final Executor mExecutor; + private final Object mInterfaceLock = new Object(); + private ICameraInjectionSession mInjectionSession; + + public CameraInjectionSessionImpl(InjectionStatusCallback callback, Executor executor) { + mInjectionStatusCallback = callback; + mExecutor = executor; + } + + @Override + public void close() { + synchronized (mInterfaceLock) { + try { + if (mInjectionSession != null) { + mInjectionSession.stopInjection(); + mInjectionSession.asBinder().unlinkToDeath(this, /*flags*/0); + mInjectionSession = null; + } + } catch (RemoteException e) { + // Ignore binder errors for disconnect + } + } + } + + @Override + protected void finalize() throws Throwable { + try { + close(); + } finally { + super.finalize(); + } + } + + @Override + public void binderDied() { + synchronized (mInterfaceLock) { + Log.w(TAG, "CameraInjectionSessionImpl died unexpectedly"); + + if (mInjectionSession == null) { + return; // CameraInjectionSession already closed + } + + Runnable r = new Runnable() { + @Override + public void run() { + mInjectionStatusCallback.onInjectionError( + CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SERVICE); + } + }; + final long ident = Binder.clearCallingIdentity(); + try { + CameraInjectionSessionImpl.this.mExecutor.execute(r); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + public CameraInjectionCallback getCallback() { + return mCallback; + } + + /** + * Set remote injection session, which triggers initial onInjectionSucceeded callbacks. + * + * <p>This function may post onInjectionError if remoteInjectionSession dies + * during injecting.</p> + */ + public void setRemoteInjectionSession(ICameraInjectionSession injectionSession) { + synchronized (mInterfaceLock) { + if (injectionSession == null) { + Log.e(TAG, "The camera injection session has encountered a serious error"); + scheduleNotifyError( + CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SESSION); + return; + } + + mInjectionSession = injectionSession; + + IBinder remoteSessionBinder = injectionSession.asBinder(); + if (remoteSessionBinder == null) { + Log.e(TAG, "The camera injection session has encountered a serious error"); + scheduleNotifyError( + CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SESSION); + return; + } + + final long ident = Binder.clearCallingIdentity(); + try { + remoteSessionBinder.linkToDeath(this, /*flag*/ 0); + mExecutor.execute(new Runnable() { + @Override + public void run() { + mInjectionStatusCallback + .onInjectionSucceeded(CameraInjectionSessionImpl.this); + } + }); + } catch (RemoteException e) { + scheduleNotifyError( + CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SESSION); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + /** + * The method called when the injection camera has encountered a serious error. + * + * @param errorCode The error code. + * @see #ERROR_INJECTION_SESSION + * @see #ERROR_INJECTION_SERVICE + * @see #ERROR_INJECTION_UNSUPPORTED + */ + public void onInjectionError(final int errorCode) { + Log.v(TAG, String.format( + "Injection session error received, code %d", errorCode)); + + synchronized (mInterfaceLock) { + if (mInjectionSession == null) { + return; // mInjectionSession already closed + } + + switch (errorCode) { + case CameraInjectionCallback.ERROR_INJECTION_SESSION: + scheduleNotifyError( + CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SESSION); + break; + case CameraInjectionCallback.ERROR_INJECTION_SERVICE: + scheduleNotifyError( + CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SERVICE); + break; + case CameraInjectionCallback.ERROR_INJECTION_UNSUPPORTED: + scheduleNotifyError( + CameraInjectionSession.InjectionStatusCallback + .ERROR_INJECTION_UNSUPPORTED); + break; + default: + Log.e(TAG, "Unknown error from injection session: " + errorCode); + scheduleNotifyError( + CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_SERVICE); + } + } + } + + private void scheduleNotifyError(final int errorCode) { + final long ident = Binder.clearCallingIdentity(); + try { + mExecutor.execute(obtainRunnable( + CameraInjectionSessionImpl::notifyError, + this, errorCode).recycleOnUse()); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private void notifyError(final int errorCode) { + if (mInjectionSession != null) { + mInjectionStatusCallback.onInjectionError(errorCode); + } + } + + /** + * The class inherits ICameraInjectionCallbacks.Stub. Use CameraManager#injectCamera to + * instantiate. + */ + public class CameraInjectionCallback extends ICameraInjectionCallback.Stub { + + @Override + public IBinder asBinder() { + return this; + } + + @Override + public void onInjectionError(int errorCode) { + CameraInjectionSessionImpl.this.onInjectionError(errorCode); + } + } +} diff --git a/core/java/android/hardware/face/FaceEnrollFrame.java b/core/java/android/hardware/face/FaceEnrollFrame.java index 551139d240a3..822a57944449 100644 --- a/core/java/android/hardware/face/FaceEnrollFrame.java +++ b/core/java/android/hardware/face/FaceEnrollFrame.java @@ -18,6 +18,7 @@ package android.hardware.face; import android.annotation.NonNull; import android.annotation.Nullable; +import android.hardware.face.FaceEnrollStages.FaceEnrollStage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/hardware/face/FaceEnrollStage.java b/core/java/android/hardware/face/FaceEnrollStages.java index de717fbe46b4..de374b319ff9 100644 --- a/core/java/android/hardware/face/FaceEnrollStage.java +++ b/core/java/android/hardware/face/FaceEnrollStages.java @@ -22,53 +22,63 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * A stage that may occur during face enrollment. + * A collection of constants representing different stages of face enrollment. * * @hide */ -@Retention(RetentionPolicy.SOURCE) -@IntDef({ - FaceEnrollStage.UNKNOWN, - FaceEnrollStage.FIRST_FRAME_RECEIVED, - FaceEnrollStage.WAITING_FOR_CENTERING, - FaceEnrollStage.HOLD_STILL_IN_CENTER, - FaceEnrollStage.ENROLLING_MOVEMENT_1, - FaceEnrollStage.ENROLLING_MOVEMENT_2, - FaceEnrollStage.ENROLLMENT_FINISHED -}) -public @interface FaceEnrollStage { +public final class FaceEnrollStages { + // Prevent instantiation. + private FaceEnrollStages() {} + + /** + * A stage that may occur during face enrollment. + * + * @hide + */ + @IntDef({ + UNKNOWN, + FIRST_FRAME_RECEIVED, + WAITING_FOR_CENTERING, + HOLD_STILL_IN_CENTER, + ENROLLING_MOVEMENT_1, + ENROLLING_MOVEMENT_2, + ENROLLMENT_FINISHED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FaceEnrollStage {} + /** * The current enrollment stage is not known. */ - int UNKNOWN = -1; + public static final int UNKNOWN = 0; /** * Enrollment has just begun. No action is needed from the user yet. */ - int FIRST_FRAME_RECEIVED = 0; + public static final int FIRST_FRAME_RECEIVED = 1; /** * The user must center their face in the frame. */ - int WAITING_FOR_CENTERING = 1; + public static final int WAITING_FOR_CENTERING = 2; /** * The user must keep their face centered in the frame. */ - int HOLD_STILL_IN_CENTER = 2; + public static final int HOLD_STILL_IN_CENTER = 3; /** * The user must follow a first set of movement instructions. */ - int ENROLLING_MOVEMENT_1 = 3; + public static final int ENROLLING_MOVEMENT_1 = 4; /** * The user must follow a second set of movement instructions. */ - int ENROLLING_MOVEMENT_2 = 4; + public static final int ENROLLING_MOVEMENT_2 = 5; /** * Enrollment has completed. No more action is needed from the user. */ - int ENROLLMENT_FINISHED = 5; + public static final int ENROLLMENT_FINISHED = 6; } diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 13e2700b3f54..9a27a99437bc 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -133,11 +133,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } @Override - public void onFeatureGet(boolean success, int feature, boolean value) { + public void onFeatureGet(boolean success, int[] features, boolean[] featureState) { SomeArgs args = SomeArgs.obtain(); args.arg1 = success; - args.argi1 = feature; - args.arg2 = value; + args.arg2 = features; + args.arg3 = featureState; mHandler.obtainMessage(MSG_GET_FEATURE_COMPLETED, args).sendToTarget(); } @@ -1023,6 +1023,34 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } /** + * Called each time a single frame is captured during enrollment. + * + * <p>For older, non-AIDL implementations, only {@code helpCode} and {@code helpMessage} are + * supported. Sensible default values will be provided for all other arguments. + * + * @param helpCode An integer identifying the capture status for this frame. + * @param helpMessage A human-readable help string that can be shown in UI. + * @param cell The cell captured during this frame of enrollment, if any. + * @param stage An integer representing the current stage of enrollment. + * @param pan The horizontal pan of the detected face. Values in the range [-1, 1] + * indicate a good capture. + * @param tilt The vertical tilt of the detected face. Values in the range [-1, 1] + * indicate a good capture. + * @param distance The distance of the detected face from the device. Values in + * the range [-1, 1] indicate a good capture. + */ + public void onEnrollmentFrame( + int helpCode, + @Nullable CharSequence helpMessage, + @Nullable FaceEnrollCell cell, + @FaceEnrollStages.FaceEnrollStage int stage, + float pan, + float tilt, + float distance) { + onEnrollmentHelp(helpCode, helpMessage); + } + + /** * Called as each enrollment step progresses. Enrollment is considered complete when * remaining reaches 0. This function will not be called if enrollment fails. See * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} @@ -1088,7 +1116,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * @hide */ public abstract static class GetFeatureCallback { - public abstract void onCompleted(boolean success, int feature, boolean value); + public abstract void onCompleted(boolean success, int[] features, boolean[] featureState); } /** @@ -1179,8 +1207,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan case MSG_GET_FEATURE_COMPLETED: SomeArgs args = (SomeArgs) msg.obj; sendGetFeatureCompleted((boolean) args.arg1 /* success */, - args.argi1 /* feature */, - (boolean) args.arg2 /* value */); + (int[]) args.arg2 /* features */, + (boolean[]) args.arg3 /* featureState */); args.recycle(); break; case MSG_CHALLENGE_GENERATED: @@ -1216,11 +1244,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan mSetFeatureCallback.onCompleted(success, feature); } - private void sendGetFeatureCompleted(boolean success, int feature, boolean value) { + private void sendGetFeatureCompleted(boolean success, int[] features, boolean[] featureState) { if (mGetFeatureCallback == null) { return; } - mGetFeatureCallback.onCompleted(success, feature, value); + mGetFeatureCallback.onCompleted(success, features, featureState); } private void sendChallengeGenerated(int sensorId, long challenge) { @@ -1305,7 +1333,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } else if (mEnrollmentCallback != null) { final FaceEnrollFrame frame = new FaceEnrollFrame( null /* cell */, - FaceEnrollStage.UNKNOWN, + FaceEnrollStages.UNKNOWN, new FaceDataFrame(acquireInfo, vendorCode)); sendEnrollmentFrame(frame); } @@ -1333,12 +1361,19 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan if (frame == null) { Slog.w(TAG, "Received null enrollment frame"); } else if (mEnrollmentCallback != null) { - // TODO(b/178414967): Send additional frame data to callback - final int acquireInfo = frame.getData().getAcquiredInfo(); - final int vendorCode = frame.getData().getVendorCode(); + final FaceDataFrame data = frame.getData(); + final int acquireInfo = data.getAcquiredInfo(); + final int vendorCode = data.getVendorCode(); final int helpCode = getHelpCode(acquireInfo, vendorCode); final String helpMessage = getEnrollHelpMessage(mContext, acquireInfo, vendorCode); - mEnrollmentCallback.onEnrollmentHelp(helpCode, helpMessage); + mEnrollmentCallback.onEnrollmentFrame( + helpCode, + helpMessage, + frame.getCell(), + frame.getStage(), + data.getPan(), + data.getTilt(), + data.getDistance()); } } diff --git a/core/java/android/hardware/face/FaceServiceReceiver.java b/core/java/android/hardware/face/FaceServiceReceiver.java index f0f975dcea57..9e62ca5e466b 100644 --- a/core/java/android/hardware/face/FaceServiceReceiver.java +++ b/core/java/android/hardware/face/FaceServiceReceiver.java @@ -66,7 +66,8 @@ public class FaceServiceReceiver extends IFaceServiceReceiver.Stub { } @Override - public void onFeatureGet(boolean success, int feature, boolean value) throws RemoteException { + public void onFeatureGet(boolean success, int[] features, boolean[] featureState) + throws RemoteException { } diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index 0b44150afa4d..270d662a02a0 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -127,6 +127,8 @@ interface IFaceService { void getFeature(IBinder token, int userId, int feature, IFaceServiceReceiver receiver, String opPackageName); - // Give FaceService its ID. See AuthService.java - void initializeConfiguration(int sensorId, int strength); + // Registers all HIDL and AIDL sensors. Only HIDL sensor properties need to be provided, because + // AIDL sensor properties are retrieved directly from the available HALs. If no HIDL HALs exist, + // hidlSensors must be non-null and empty. See AuthService.java + void registerAuthenticators(in List<FaceSensorPropertiesInternal> hidlSensors); } diff --git a/core/java/android/hardware/face/IFaceServiceReceiver.aidl b/core/java/android/hardware/face/IFaceServiceReceiver.aidl index 2ef1430a2f99..0ccb39583554 100644 --- a/core/java/android/hardware/face/IFaceServiceReceiver.aidl +++ b/core/java/android/hardware/face/IFaceServiceReceiver.aidl @@ -32,7 +32,7 @@ oneway interface IFaceServiceReceiver { void onError(int error, int vendorCode); void onRemoved(in Face face, int remaining); void onFeatureSet(boolean success, int feature); - void onFeatureGet(boolean success, int feature, boolean value); + void onFeatureGet(boolean success, in int[] features, in boolean[] featureState); void onChallengeGenerated(int sensorId, long challenge); void onChallengeInterrupted(int sensorId); void onChallengeInterruptFinished(int sensorId); diff --git a/core/java/android/hardware/face/OWNERS b/core/java/android/hardware/face/OWNERS index be10df1099ed..0b4d9d9d6f54 100644 --- a/core/java/android/hardware/face/OWNERS +++ b/core/java/android/hardware/face/OWNERS @@ -1,7 +1,3 @@ # Bug component: 879035 -curtislb@google.com -ilyamaty@google.com -jaggies@google.com -joshmccloskey@google.com -kchyn@google.com +include /services/core/java/com/android/server/biometrics/OWNERS diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 88d5ba8be8ab..cc1aeeb92685 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -1013,6 +1013,31 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } /** + * Adds a callback that gets called when the service registers all of the fingerprint + * authenticators (HALs). + * + * If the fingerprint authenticators are already registered when the callback is added, the + * callback is invoked immediately. + * + * The callback is automatically removed after it's invoked. + * + * @hide + */ + @RequiresPermission(USE_BIOMETRIC_INTERNAL) + public void addAuthenticatorsRegisteredCallback( + IFingerprintAuthenticatorsRegisteredCallback callback) { + if (mService != null) { + try { + mService.addAuthenticatorsRegisteredCallback(callback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } else { + Slog.w(TAG, "addProvidersAvailableCallback(): Service not connected!"); + } + } + + /** * @hide */ public void addLockoutResetCallback(final LockoutResetCallback callback) { diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java index 58f6e62af320..4ffe5f189661 100644 --- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java +++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java @@ -20,7 +20,6 @@ import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFP import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC; import android.annotation.NonNull; -import android.content.Context; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; import android.hardware.biometrics.SensorPropertiesInternal; @@ -92,34 +91,6 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna 1636 /* sensorLocationY */, 130 /* sensorRadius */); } - /** - * Initializes SensorProperties with specified values and values obtained from resources using - * context. - */ - // TODO(b/179175438): Remove this constructor once all HALs move to AIDL. - public FingerprintSensorPropertiesInternal(@NonNull Context context, int sensorId, - @SensorProperties.Strength int strength, int maxEnrollmentsPerUser, - @NonNull List<ComponentInfoInternal> componentInfo, - @FingerprintSensorProperties.SensorType int sensorType, - boolean resetLockoutRequiresHardwareAuthToken) { - super(sensorId, strength, maxEnrollmentsPerUser, componentInfo, - resetLockoutRequiresHardwareAuthToken, false /* resetLockoutRequiresChallenge */); - this.sensorType = sensorType; - - int[] props = context.getResources().getIntArray( - com.android.internal.R.array.config_udfps_sensor_props); - if (props != null && props.length == 3) { - this.sensorLocationX = props[0]; - this.sensorLocationY = props[1]; - this.sensorRadius = props[2]; - } else { - // Fake coordinates that could be used for the fake UDFPS mode. - this.sensorLocationX = 540; - this.sensorLocationY = 1636; - this.sensorRadius = 130; - } - } - protected FingerprintSensorPropertiesInternal(Parcel in) { super(in); sensorType = in.readInt(); diff --git a/core/java/android/hardware/fingerprint/IFingerprintAuthenticatorsRegisteredCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintAuthenticatorsRegisteredCallback.aidl new file mode 100644 index 000000000000..5a2c9311eaf9 --- /dev/null +++ b/core/java/android/hardware/fingerprint/IFingerprintAuthenticatorsRegisteredCallback.aidl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.fingerprint; + +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import java.util.List; + +/** + * Callback to notify FingerprintManager that FingerprintService has registered all of the + * fingerprint authenticators (HALs). + * See {@link android.hardware.fingerprint.IFingerprintService#registerAuthenticators}. + * + * @hide + */ +oneway interface IFingerprintAuthenticatorsRegisteredCallback { + /** + * Notifies FingerprintManager that all of the fingerprint authenticators have been registered. + * + * @param sensors A consolidated list of sensor properties for all of the authenticators. + */ + void onAllAuthenticatorsRegistered(in List<FingerprintSensorPropertiesInternal> sensors); +} diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 3bceacb5e479..833747f19a0c 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -21,6 +21,7 @@ import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.fingerprint.IFingerprintClientActiveCallback; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.IFingerprintStateListener; import android.hardware.fingerprint.IUdfpsOverlayController; @@ -144,8 +145,14 @@ interface IFingerprintService { // Removes a callback set by addClientActiveCallback void removeClientActiveCallback(IFingerprintClientActiveCallback callback); - // Give FingerprintService its ID. See AuthService.java - void initializeConfiguration(int sensorId, int strength); + // Registers all HIDL and AIDL sensors. Only HIDL sensor properties need to be provided, because + // AIDL sensor properties are retrieved directly from the available HALs. If no HIDL HALs exist, + // hidlSensors must be non-null and empty. See AuthService.java + void registerAuthenticators(in List<FingerprintSensorPropertiesInternal> hidlSensors); + + // Adds a callback which gets called when the service registers all of the fingerprint + // authenticators. The callback is automatically removed after it's invoked. + void addAuthenticatorsRegisteredCallback(IFingerprintAuthenticatorsRegisteredCallback callback); // Notifies about a finger touching the sensor area. void onPointerDown(int sensorId, int x, int y, float minor, float major); diff --git a/core/java/android/hardware/fingerprint/OWNERS b/core/java/android/hardware/fingerprint/OWNERS index e55b8c564ddb..5c9367240b8d 100644 --- a/core/java/android/hardware/fingerprint/OWNERS +++ b/core/java/android/hardware/fingerprint/OWNERS @@ -1,8 +1,3 @@ # Bug component: 114777 -curtislb@google.com -ilyamaty@google.com -jaggies@google.com -joshmccloskey@google.com -kchyn@google.com - +include /services/core/java/com/android/server/biometrics/OWNERS diff --git a/core/java/android/hardware/input/InputDeviceBattery.java b/core/java/android/hardware/input/InputDeviceBatteryState.java index 0fe124e2c0ce..d069eb0ddb81 100644 --- a/core/java/android/hardware/input/InputDeviceBattery.java +++ b/core/java/android/hardware/input/InputDeviceBatteryState.java @@ -19,28 +19,28 @@ package android.hardware.input; import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; import static android.os.IInputConstants.INVALID_BATTERY_CAPACITY; -import android.hardware.Battery; +import android.hardware.BatteryState; /** * Battery implementation for input devices. * * @hide */ -public final class InputDeviceBattery extends Battery { - private static final float NULL_BATTERY_CAPACITY = -1.0f; +public final class InputDeviceBatteryState extends BatteryState { + private static final float NULL_BATTERY_CAPACITY = Float.NaN; private final InputManager mInputManager; private final int mDeviceId; private final boolean mHasBattery; - InputDeviceBattery(InputManager inputManager, int deviceId, boolean hasBattery) { + InputDeviceBatteryState(InputManager inputManager, int deviceId, boolean hasBattery) { mInputManager = inputManager; mDeviceId = deviceId; mHasBattery = hasBattery; } @Override - public boolean hasBattery() { + public boolean isPresent() { return mHasBattery; } diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 648fda7c22bb..51d196dc8292 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1571,12 +1571,12 @@ public final class InputManager { } /** - * Gets a battery object associated with an input device, assuming it has one. + * Gets a battery state object associated with an input device, assuming it has one. * @return The battery, never null. * @hide */ - public InputDeviceBattery getInputDeviceBattery(int deviceId, boolean hasBattery) { - return new InputDeviceBattery(this, deviceId, hasBattery); + public InputDeviceBatteryState getInputDeviceBatteryState(int deviceId, boolean hasBattery) { + return new InputDeviceBatteryState(this, deviceId, hasBattery); } /** diff --git a/core/java/android/hardware/iris/IIrisService.aidl b/core/java/android/hardware/iris/IIrisService.aidl index 3d26318343be..98057d548226 100644 --- a/core/java/android/hardware/iris/IIrisService.aidl +++ b/core/java/android/hardware/iris/IIrisService.aidl @@ -15,12 +15,16 @@ */ package android.hardware.iris; +import android.hardware.biometrics.SensorPropertiesInternal; + /** * Communication channel from client to the iris service. These methods are all require the * MANAGE_BIOMETRIC signature permission. * @hide */ interface IIrisService { - // Give IrisService its ID. See AuthService.java - void initializeConfiguration(int sensorId, int strength); + // Registers all HIDL and AIDL sensors. Only HIDL sensor properties need to be provided, because + // AIDL sensor properties are retrieved directly from the available HALs. If no HIDL HALs exist, + // hidlSensors must be non-null and empty. See AuthService.java + void registerAuthenticators(in List<SensorPropertiesInternal> hidlSensors); } diff --git a/core/java/android/hardware/iris/OWNERS b/core/java/android/hardware/iris/OWNERS index 33527f824827..0b4d9d9d6f54 100644 --- a/core/java/android/hardware/iris/OWNERS +++ b/core/java/android/hardware/iris/OWNERS @@ -1,3 +1,3 @@ # Bug component: 879035 -jaggies@google.com +include /services/core/java/com/android/server/biometrics/OWNERS diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java index 7bfff5d3af97..2812868b8f92 100644 --- a/core/java/android/hardware/lights/Light.java +++ b/core/java/android/hardware/lights/Light.java @@ -37,20 +37,25 @@ public final class Light implements Parcelable { /** Type for lights that indicate microphone usage */ public static final int LIGHT_TYPE_MICROPHONE = 8; + // These enum values start from 10001 to avoid collision with expanding of HAL light types. /** * Type for lights that indicate a monochrome color LED light. */ - public static final int LIGHT_TYPE_INPUT_SINGLE = 9; + public static final int LIGHT_TYPE_INPUT_SINGLE = 10001; /** * Type for lights that indicate a group of LED lights representing player ID. + * Player ID lights normally present on game controllers are lights that consist of a row of + * LEDs. + * During multi-player game, the player ID for the current game controller is represented by + * one of the LED that is lit according to its position in the row. */ - public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10; + public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10002; /** * Type for lights that indicate a color LED light. */ - public static final int LIGHT_TYPE_INPUT_RGB = 11; + public static final int LIGHT_TYPE_INPUT_RGB = 10003; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -136,6 +141,11 @@ public final class Light implements Parcelable { return mId; } + @Override + public String toString() { + return "[Name=" + mName + " Id=" + mId + " Type=" + mType + " Ordinal=" + mOrdinal + "]"; + } + /** * Returns the id of the light. * diff --git a/core/java/android/hardware/lights/LightState.java b/core/java/android/hardware/lights/LightState.java index 650b383eeb0f..c6d7f63d90e2 100644 --- a/core/java/android/hardware/lights/LightState.java +++ b/core/java/android/hardware/lights/LightState.java @@ -18,6 +18,7 @@ package android.hardware.lights; import android.annotation.ColorInt; import android.annotation.NonNull; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -65,27 +66,61 @@ public final class LightState implements Parcelable { } /** - * Creates a new LightState with the desired color and intensity, for a light type - * of RBG color or single monochrome color. - * - * @param color the desired color and intensity in ARGB format. - * @return The LightState object contains the color. + * Builder for creating device light change requests. */ - @NonNull - public static LightState forColor(@ColorInt int color) { - return new LightState(color, 0); - } + public static final class Builder { + private int mValue; + private boolean mIsForPlayerId; - /** - * Creates a new LightState with the desired player id, for a light of type - * {@link android.hardware.lights.Light#LIGHT_TYPE_INPUT_PLAYER_ID}. - * - * @param playerId the desired player id. - * @return The LightState object contains the player id. - */ - @NonNull - public static LightState forPlayerId(int playerId) { - return new LightState(0, playerId); + /** Creates a new {@link LightState.Builder}. */ + public Builder() { + mValue = 0; + mIsForPlayerId = false; + } + + /** + * Set the desired color and intensity of the LightState Builder, for a light type + * of RBG color or single monochrome color. + * + * @param color the desired color and intensity in ARGB format. + * @return The {@link LightState.Builder} object contains the light color and intensity. + */ + @SuppressLint("MissingGetterMatchingBuilder") + @NonNull + public Builder setColor(@ColorInt int color) { + mIsForPlayerId = false; + mValue = color; + return this; + } + + /** + * Set the desired player id of the LightState Builder, for a light of type + * {@link android.hardware.lights.Light#LIGHT_TYPE_INPUT_PLAYER_ID}. + * + * @param playerId the desired player id. + * @return The {@link LightState.Builder} object contains the player id. + */ + @SuppressLint("MissingGetterMatchingBuilder") + @NonNull + public Builder setPlayerId(int playerId) { + mIsForPlayerId = true; + mValue = playerId; + return this; + } + + /** + * Create a LightState object used to control lights on the device. + * + * <p>The generated {@link LightState} should be used in + * {@link LightsRequest.Builder#addLight(Light, LightState)}. + */ + public @NonNull LightState build() { + if (!mIsForPlayerId) { + return new LightState(mValue, 0); + } else { + return new LightState(0, mValue); + } + } } /** diff --git a/core/java/android/hardware/lights/LightsManager.java b/core/java/android/hardware/lights/LightsManager.java index 8bc86dac0a8c..2d9bc0eb14ab 100644 --- a/core/java/android/hardware/lights/LightsManager.java +++ b/core/java/android/hardware/lights/LightsManager.java @@ -99,11 +99,26 @@ public abstract class LightsManager { /** * Encapsulates a session that can be used to control device lights and represents the lifetime * of the requests. + * + * <p>Any lights requests always live in a lights session which defines the lifecycle of the + * lights requests. A lights session is AutoCloseable that will get closed when leaving the + * session context. + * + * <p>Multiple sessions can make lights requests which contains same light. In the case the + * LightsManager implementation will arbitrate and honor one of the session's request. When + * the session hold the current light request closed, LightsManager implementation will choose + * another live session to honor its lights requests. */ public abstract static class LightsSession implements AutoCloseable { private final IBinder mToken = new Binder(); /** + * @hide to prevent subclassing from outside of the framework + */ + public LightsSession() { + } + + /** * Sends a request to modify the states of multiple lights. * * @param request the settings for lights that should change diff --git a/core/java/android/hardware/lights/LightsRequest.java b/core/java/android/hardware/lights/LightsRequest.java index 6fb0eb5df59a..8d27dfd7487b 100644 --- a/core/java/android/hardware/lights/LightsRequest.java +++ b/core/java/android/hardware/lights/LightsRequest.java @@ -24,7 +24,9 @@ import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Encapsulates a request to modify the state of multiple lights. * @@ -51,7 +53,7 @@ public final class LightsRequest { } /** - * Get a list of Light as ids. The ids will returned in same order as the lights passed + * Get a list of Light as ids. The ids will returned in same order as the lights passed * in Builder. * * @return List of light ids @@ -75,6 +77,18 @@ public final class LightsRequest { } /** + * Get a map of light ids and states. The map will contain all the light ids as keys and + * the corresponding LightState requested as values. + */ + public @NonNull Map<Integer, LightState> getLightsAndStates() { + Map<Integer, LightState> map = new HashMap<>(); + for (int i = 0; i < mLightIds.length; i++) { + map.put(mLightIds[i], mLightStates[i]); + } + return map; + } + + /** * Builder for creating device light change requests. */ public static final class Builder { diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java index 0766917642e8..5a517ee0b0eb 100644 --- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -49,7 +49,6 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub private static final int DO_UPDATE_CURSOR = 95; private static final int DO_UPDATE_CURSOR_ANCHOR_INFO = 99; private static final int DO_APP_PRIVATE_COMMAND = 100; - private static final int DO_TOGGLE_SOFT_INPUT = 105; private static final int DO_FINISH_SESSION = 110; private static final int DO_VIEW_CLICKED = 115; private static final int DO_NOTIFY_IME_HIDDEN = 120; @@ -123,10 +122,6 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub args.recycle(); return; } - case DO_TOGGLE_SOFT_INPUT: { - mInputMethodSession.toggleSoftInput(msg.arg1, msg.arg2); - return; - } case DO_FINISH_SESSION: { doFinishSession(); return; @@ -218,12 +213,6 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub } @Override - public void toggleSoftInput(int showFlags, int hideFlags) { - mCaller.executeOrSendMessage( - mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags)); - } - - @Override public void finishSession() { mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_SESSION)); } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 5267aa81bdaf..d7b96dfb7827 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1042,8 +1042,14 @@ public class InputMethodService extends AbstractInputMethodService { } /** - * + * Handles a request to toggle the IME visibility. + * + * @deprecated Starting in {@link Build.VERSION_CODES#S} the system no longer invokes this + * method, instead it explicitly shows or hides the IME. An {@code InputMethodService} + * wishing to toggle its own visibility should instead invoke {@link + * InputMethodService#requestShowSelf} or {@link InputMethodService#requestHideSelf} */ + @Deprecated public void toggleSoftInput(int showFlags, int hideFlags) { InputMethodService.this.onToggleSoftInput(showFlags, hideFlags); } @@ -1941,12 +1947,12 @@ public class InputMethodService extends AbstractInputMethodService { public void showStatusIcon(@DrawableRes int iconResId) { mStatusIcon = iconResId; - mPrivOps.updateStatusIcon(getPackageName(), iconResId); + mPrivOps.updateStatusIconAsync(getPackageName(), iconResId); } public void hideStatusIcon() { mStatusIcon = 0; - mPrivOps.updateStatusIcon(null, 0); + mPrivOps.updateStatusIconAsync(null, 0); } /** @@ -2306,7 +2312,7 @@ public class InputMethodService extends AbstractInputMethodService { if (setVisible) { cancelImeSurfaceRemoval(); } - mPrivOps.applyImeVisibility(setVisible + mPrivOps.applyImeVisibilityAsync(setVisible ? mCurShowInputToken : mCurHideInputToken, setVisible); } @@ -3313,7 +3319,7 @@ public class InputMethodService extends AbstractInputMethodService { if (mNotifyUserActionSent) { return; } - mPrivOps.notifyUserAction(); + mPrivOps.notifyUserActionAsync(); mNotifyUserActionSent = true; } } diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java index 2db9ed1103fa..f352f05d0488 100644 --- a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java +++ b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java @@ -257,18 +257,6 @@ final class MultiClientInputMethodClientCallbackAdaptor { } @Override - public void toggleSoftInput(int showFlags, int hideFlags) { - synchronized (mSessionLock) { - if (mCallbackImpl == null || mHandler == null) { - return; - } - mHandler.sendMessage(PooledLambda.obtainMessage( - CallbackImpl::toggleSoftInput, mCallbackImpl, showFlags, - hideFlags)); - } - } - - @Override public void finishSession() { synchronized (mSessionLock) { if (mCallbackImpl == null || mHandler == null) { @@ -419,13 +407,6 @@ final class MultiClientInputMethodClientCallbackAdaptor { mOriginalCallback.onAppPrivateCommand(action, data); } - void toggleSoftInput(int showFlags, int hideFlags) { - if (mFinished) { - return; - } - mOriginalCallback.onToggleSoftInput(showFlags, hideFlags); - } - void finishSession() { if (mFinished) { return; diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java index 4b02085726f1..0a2316508f09 100644 --- a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java +++ b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java @@ -167,16 +167,6 @@ public final class MultiClientInputMethodServiceDelegate { /** * Called when the associated IME client called {@link - * android.view.inputmethod.InputMethodManager#toggleSoftInput(int, int)}. - * - * @param showFlags The flag passed by the client. - * @param hideFlags The flag passed by the client. - * @see android.inputmethodservice.InputMethodService#onToggleSoftInput(int, int) - */ - void onToggleSoftInput(int showFlags, int hideFlags); - - /** - * Called when the associated IME client called {@link * android.view.inputmethod.InputMethodManager#updateCursorAnchorInfo(View, * CursorAnchorInfo)}. * diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index c83dd99c2a3b..d3c89574944f 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -82,6 +82,24 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_WIFI_WILDCARD = 7; public static final int MATCH_BLUETOOTH = 8; public static final int MATCH_PROXY = 9; + public static final int MATCH_CARRIER = 10; + + /** + * Value of the match rule of the subscriberId to match networks with specific subscriberId. + */ + public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0; + /** + * Value of the match rule of the subscriberId to match networks with any subscriberId which + * includes null and non-null. + */ + public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; + + /** + * Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that + * should be fixed), so it's not possible to want to match null vs + * non-null. Therefore it's fine to use null as a sentinel for Network ID. + */ + public static final String WIFI_NETWORKID_ALL = null; /** * Include all network types when filtering. This is meant to merge in with the @@ -125,6 +143,7 @@ public class NetworkTemplate implements Parcelable { case MATCH_WIFI_WILDCARD: case MATCH_BLUETOOTH: case MATCH_PROXY: + case MATCH_CARRIER: return true; default: @@ -168,10 +187,12 @@ public class NetworkTemplate implements Parcelable { @NetworkType int ratType) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @@ -189,6 +210,8 @@ public class NetworkTemplate implements Parcelable { */ @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifiWildcard() { + // TODO: Consider replace this with MATCH_WIFI with NETWORK_ID_ALL + // and SUBSCRIBER_ID_MATCH_RULE_ALL. return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); } @@ -202,8 +225,27 @@ public class NetworkTemplate implements Parcelable { * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the * given SSID. */ - public static NetworkTemplate buildTemplateWifi(String networkId) { - return new NetworkTemplate(MATCH_WIFI, null, networkId); + public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) { + Objects.requireNonNull(networkId); + return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */, + new String[] { null } /* matchSubscriberIds */, + networkId, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_ALL); + } + + /** + * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID, + * and IMSI. + * + * Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID. + */ + public static NetworkTemplate buildTemplateWifi(@Nullable String networkId, + @Nullable String subscriberId) { + return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId }, + networkId, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @@ -231,6 +273,14 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_PROXY, null, null); } + /** + * Template to match all carrier networks with the given IMSI. + */ + public static NetworkTemplate buildTemplateCarrier(@NonNull String subscriberId) { + Objects.requireNonNull(subscriberId); + return new NetworkTemplate(MATCH_CARRIER, subscriberId, null); + } + private final int mMatchRule; private final String mSubscriberId; @@ -251,10 +301,26 @@ public class NetworkTemplate implements Parcelable { private final int mRoaming; private final int mDefaultNetwork; private final int mSubType; + private final int mSubscriberIdMatchRule; // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. private final int mOemManaged; + private void checkValidSubscriberIdMatchRule() { + switch (mMatchRule) { + case MATCH_MOBILE: + case MATCH_CARRIER: + // MOBILE and CARRIER templates must always specify a subscriber ID. + if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { + throw new IllegalArgumentException("Invalid SubscriberIdMatchRule" + + "on match rule: " + getMatchRuleName(mMatchRule)); + } + return; + default: + return; + } + } + @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -263,14 +329,25 @@ public class NetworkTemplate implements Parcelable { 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, OEM_MANAGED_ALL); + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } + // TODO: Remove it after updating all of the caller. public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork, int subType, int oemManaged) { + this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming, + defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT); + } + + public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, + String networkId, int metered, int roaming, int defaultNetwork, int subType, + int oemManaged, int subscriberIdMatchRule) { mMatchRule = matchRule; mSubscriberId = subscriberId; + // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when + // mSubscriberId is null mMatchSubscriberIds = matchSubscriberIds; mNetworkId = networkId; mMetered = metered; @@ -278,7 +355,8 @@ public class NetworkTemplate implements Parcelable { mDefaultNetwork = defaultNetwork; mSubType = subType; mOemManaged = oemManaged; - + mSubscriberIdMatchRule = subscriberIdMatchRule; + checkValidSubscriberIdMatchRule(); if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule + " will not match any identity."); @@ -295,6 +373,7 @@ public class NetworkTemplate implements Parcelable { mDefaultNetwork = in.readInt(); mSubType = in.readInt(); mOemManaged = in.readInt(); + mSubscriberIdMatchRule = in.readInt(); } @Override @@ -308,6 +387,7 @@ public class NetworkTemplate implements Parcelable { dest.writeInt(mDefaultNetwork); dest.writeInt(mSubType); dest.writeInt(mOemManaged); + dest.writeInt(mSubscriberIdMatchRule); } @Override @@ -346,13 +426,15 @@ public class NetworkTemplate implements Parcelable { if (mOemManaged != OEM_MANAGED_ALL) { builder.append(", oemManaged=").append(mOemManaged); } + builder.append(", subscriberIdMatchRule=") + .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule)); return builder.toString(); } @Override public int hashCode() { return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, - mDefaultNetwork, mSubType, mOemManaged); + mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule); } @Override @@ -366,11 +448,23 @@ public class NetworkTemplate implements Parcelable { && mRoaming == other.mRoaming && mDefaultNetwork == other.mDefaultNetwork && mSubType == other.mSubType - && mOemManaged == other.mOemManaged; + && mOemManaged == other.mOemManaged + && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule; } return false; } + private String subscriberIdMatchRuleToString(int rule) { + switch (rule) { + case SUBSCRIBER_ID_MATCH_RULE_EXACT: + return "EXACT_MATCH"; + case SUBSCRIBER_ID_MATCH_RULE_ALL: + return "ALL"; + default: + return "Unknown rule " + rule; + } + } + public boolean isMatchRuleMobile() { switch (mMatchRule) { case MATCH_MOBILE: @@ -386,6 +480,14 @@ public class NetworkTemplate implements Parcelable { case MATCH_MOBILE_WILDCARD: case MATCH_WIFI_WILDCARD: return false; + case MATCH_CARRIER: + return mSubscriberId != null; + case MATCH_WIFI: + if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) + && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { + return false; + } + return true; default: return true; } @@ -405,6 +507,10 @@ public class NetworkTemplate implements Parcelable { return mNetworkId; } + public int getSubscriberIdMatchRule() { + return mSubscriberIdMatchRule; + } + /** * Test if given {@link NetworkIdentity} matches this template. */ @@ -429,6 +535,8 @@ public class NetworkTemplate implements Parcelable { return matchesBluetooth(ident); case MATCH_PROXY: return matchesProxy(ident); + case MATCH_CARRIER: + return matchesCarrier(ident); default: // We have no idea what kind of network template we are, so we // just claim not to match anything. @@ -466,8 +574,23 @@ public class NetworkTemplate implements Parcelable { || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); } - public boolean matchesSubscriberId(String subscriberId) { - return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); + /** + * Check if this template matches {@code subscriberId}. Returns true if this + * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a + * {@code mMatchSubscriberIds} array that contains {@code subscriberId}. + */ + public boolean matchesSubscriberId(@Nullable String subscriberId) { + return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL + || ArrayUtils.contains(mMatchSubscriberIds, subscriberId); + } + + /** + * Check if network with matching SSID. Returns true when the SSID matches, or when + * {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}. + */ + private boolean matchesWifiNetworkId(@Nullable String networkId) { + return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) + || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId)); } /** @@ -566,8 +689,8 @@ public class NetworkTemplate implements Parcelable { private boolean matchesWifi(NetworkIdentity ident) { switch (ident.mType) { case TYPE_WIFI: - return Objects.equals( - sanitizeSsid(mNetworkId), sanitizeSsid(ident.mNetworkId)); + return matchesSubscriberId(ident.mSubscriberId) + && matchesWifiNetworkId(ident.mNetworkId); default: return false; } @@ -583,6 +706,15 @@ public class NetworkTemplate implements Parcelable { return false; } + /** + * Check if matches carrier network. The carrier networks means it includes the subscriberId. + */ + private boolean matchesCarrier(NetworkIdentity ident) { + return ident.mSubscriberId != null + && !ArrayUtils.isEmpty(mMatchSubscriberIds) + && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); + } + private boolean matchesMobileWildcard(NetworkIdentity ident) { if (ident.mType == TYPE_WIMAX) { return true; @@ -635,6 +767,8 @@ public class NetworkTemplate implements Parcelable { return "BLUETOOTH"; case MATCH_PROXY: return "PROXY"; + case MATCH_CARRIER: + return "CARRIER"; default: return "UNKNOWN(" + matchRule + ")"; } diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index 77c8a4f4579b..1927e20255e3 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -60,6 +60,7 @@ public final class Proxy { * {@link ConnectivityManager#getDefaultProxy()} or * {@link ConnectivityManager#getLinkProperties(Network)}.{@link LinkProperties#getHttpProxy()} * to get the proxy for the Network(s) they are using. + * @removed */ @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO"; diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java index 459fdacef816..33f9375c03bf 100644 --- a/core/java/android/net/UnderlyingNetworkInfo.java +++ b/core/java/android/net/UnderlyingNetworkInfo.java @@ -71,13 +71,13 @@ public final class UnderlyingNetworkInfo implements Parcelable { /** Get the interface name of this network. */ @NonNull - public String getIface() { + public String getInterface() { return mIface; } /** Get the names of the interfaces underlying this network. */ @NonNull - public List<String> getUnderlyingIfaces() { + public List<String> getUnderlyingInterfaces() { return mUnderlyingIfaces; } @@ -124,8 +124,8 @@ public final class UnderlyingNetworkInfo implements Parcelable { if (!(o instanceof UnderlyingNetworkInfo)) return false; final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o; return mOwnerUid == that.getOwnerUid() - && Objects.equals(mIface, that.getIface()) - && Objects.equals(mUnderlyingIfaces, that.getUnderlyingIfaces()); + && Objects.equals(mIface, that.getInterface()) + && Objects.equals(mUnderlyingIfaces, that.getUnderlyingInterfaces()); } @Override diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java index 3c02cf05dea3..f02346b6331b 100644 --- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java @@ -24,7 +24,7 @@ import android.annotation.Nullable; import android.annotation.SuppressLint; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.TunnelConnectionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils; import android.os.PersistableBundle; import android.util.ArraySet; @@ -141,7 +141,7 @@ public final class VcnGatewayConnectionConfig { * <p>To ensure the device is not constantly being woken up, this retry interval MUST be greater * than this value. * - * @see {@link Builder#setRetryIntervalsMs()} + * @see {@link Builder#setRetryIntervalsMillis()} */ private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15); @@ -159,7 +159,7 @@ public final class VcnGatewayConnectionConfig { @NonNull private final String mGatewayConnectionName; private static final String TUNNEL_CONNECTION_PARAMS_KEY = "mTunnelConnectionParams"; - @NonNull private TunnelConnectionParams mTunnelConnectionParams; + @NonNull private IkeTunnelConnectionParams mTunnelConnectionParams; private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; @NonNull private final SortedSet<Integer> mExposedCapabilities; @@ -176,7 +176,7 @@ public final class VcnGatewayConnectionConfig { /** Builds a VcnGatewayConnectionConfig with the specified parameters. */ private VcnGatewayConnectionConfig( @NonNull String gatewayConnectionName, - @NonNull TunnelConnectionParams tunnelConnectionParams, + @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set<Integer> exposedCapabilities, @NonNull Set<Integer> underlyingCapabilities, @NonNull long[] retryIntervalsMs, @@ -276,7 +276,7 @@ public final class VcnGatewayConnectionConfig { * @hide */ @NonNull - public TunnelConnectionParams getTunnelConnectionParams() { + public IkeTunnelConnectionParams getTunnelConnectionParams() { return mTunnelConnectionParams; } @@ -342,10 +342,10 @@ public final class VcnGatewayConnectionConfig { /** * Retrieves the configured retry intervals. * - * @see Builder#setRetryIntervalsMs(long[]) + * @see Builder#setRetryIntervalsMillis(long[]) */ @NonNull - public long[] getRetryIntervalsMs() { + public long[] getRetryIntervalsMillis() { return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); } @@ -419,7 +419,7 @@ public final class VcnGatewayConnectionConfig { */ public static final class Builder { @NonNull private final String mGatewayConnectionName; - @NonNull private final TunnelConnectionParams mTunnelConnectionParams; + @NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams; @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet(); @NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet(); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; @@ -437,13 +437,13 @@ public final class VcnGatewayConnectionConfig { * VcnConfig} must be given a unique name. This name is used by the caller to * distinguish between VcnGatewayConnectionConfigs configured on a single {@link * VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations. - * @param tunnelConnectionParams the tunnel connection configuration - * @see TunnelConnectionParams + * @param tunnelConnectionParams the IKE tunnel connection configuration + * @see IkeTunnelConnectionParams * @see VcnManager.VcnStatusCallback#onGatewayConnectionError */ public Builder( @NonNull String gatewayConnectionName, - @NonNull TunnelConnectionParams tunnelConnectionParams) { + @NonNull IkeTunnelConnectionParams tunnelConnectionParams) { Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null"); Objects.requireNonNull(tunnelConnectionParams, "tunnelConnectionParams was null"); @@ -555,7 +555,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnManager for additional discussion on fail-safe mode */ @NonNull - public Builder setRetryIntervalsMs(@NonNull long[] retryIntervalsMs) { + public Builder setRetryIntervalsMillis(@NonNull long[] retryIntervalsMs) { validateRetryInterval(retryIntervalsMs); mRetryIntervalsMs = retryIntervalsMs; diff --git a/core/java/android/net/vcn/VcnTransportInfo.java b/core/java/android/net/vcn/VcnTransportInfo.java index 4d8cf91621ba..0e9ccf144c2e 100644 --- a/core/java/android/net/vcn/VcnTransportInfo.java +++ b/core/java/android/net/vcn/VcnTransportInfo.java @@ -16,14 +16,23 @@ package android.net.vcn; +import static android.net.NetworkCapabilities.REDACT_ALL; +import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + +import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.NetworkCapabilities; import android.net.TransportInfo; import android.net.wifi.WifiInfo; import android.os.Parcel; import android.os.Parcelable; import android.telephony.SubscriptionManager; +import com.android.internal.annotations.VisibleForTesting; + import java.util.Objects; /** @@ -37,28 +46,41 @@ import java.util.Objects; * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. If the underlying Network is Cellular, the WifiInfo * will be {@code null}. * + * <p>Receipt of a VcnTransportInfo requires the NETWORK_SETTINGS permission; else the entire + * VcnTransportInfo instance will be redacted. + * * @hide */ public class VcnTransportInfo implements TransportInfo, Parcelable { @Nullable private final WifiInfo mWifiInfo; private final int mSubId; + /** + * The redaction scheme to use when parcelling. + * + * <p>The TransportInfo/NetworkCapabilities redaction mechanisms rely on redaction being + * performed at parcelling time. This means that the redaction scheme must be stored for later + * use. + * + * <p>Since the redaction scheme itself is not parcelled, this field is listed as a transient. + * + * <p>Defaults to REDACT_ALL when constructed using public constructors, or creating from + * parcels. + */ + private final transient long mRedactions; + public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { - this(wifiInfo, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + this(wifiInfo, INVALID_SUBSCRIPTION_ID, REDACT_ALL); } public VcnTransportInfo(int subId) { - this(null /* wifiInfo */, subId); + this(null /* wifiInfo */, subId, REDACT_ALL); } - private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId) { - if (wifiInfo == null && subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - throw new IllegalArgumentException( - "VcnTransportInfo requires either non-null WifiInfo or valid subId"); - } - + private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId, long redactions) { mWifiInfo = wifiInfo; mSubId = subId; + mRedactions = redactions; } /** @@ -86,8 +108,19 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return mSubId; } + /** + * Gets the redaction scheme + * + * @hide + */ + @VisibleForTesting(visibility = PRIVATE) + public long getRedaction() { + return mRedactions; + } + @Override public int hashCode() { + // mRedactions not hashed, as it is a transient, for control of parcelling return Objects.hash(mWifiInfo, mSubId); } @@ -96,6 +129,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { if (!(o instanceof VcnTransportInfo)) return false; final VcnTransportInfo that = (VcnTransportInfo) o; + // mRedactions not compared, as it is a transient, for control of parcelling return Objects.equals(mWifiInfo, that.mWifiInfo) && mSubId == that.mSubId; } @@ -105,17 +139,59 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return 0; } + @Override + @NonNull + public TransportInfo makeCopy(long redactions) { + return new VcnTransportInfo( + mWifiInfo == null ? null : mWifiInfo.makeCopy(redactions), mSubId, redactions); + } + + @Override + public long getApplicableRedactions() { + long redactions = REDACT_FOR_NETWORK_SETTINGS; + + // Add additional wifi redactions if necessary + if (mWifiInfo != null) { + redactions |= mWifiInfo.getApplicableRedactions(); + } + + return redactions; + } + + private boolean shouldParcelNetworkSettingsFields() { + return (mRedactions & NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS) == 0; + } + /** {@inheritDoc} */ @Override - public void writeToParcel(@NonNull Parcel dest, int flags) {} + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(shouldParcelNetworkSettingsFields() ? mSubId : INVALID_SUBSCRIPTION_ID); + dest.writeParcelable( + shouldParcelNetworkSettingsFields() ? (Parcelable) mWifiInfo : null, flags); + } + + @Override + public String toString() { + return "VcnTransportInfo { mWifiInfo = " + mWifiInfo + ", mSubId = " + mSubId + " }"; + } /** Implement the Parcelable interface */ public static final @NonNull Creator<VcnTransportInfo> CREATOR = new Creator<VcnTransportInfo>() { public VcnTransportInfo createFromParcel(Parcel in) { - // return null instead of a default VcnTransportInfo to avoid leaking - // information about this being a VCN Network (instead of macro cellular, etc) - return null; + final int subId = in.readInt(); + final WifiInfo wifiInfo = in.readParcelable(null); + + // If all fields are their null values, return null TransportInfo to avoid + // leaking information about this being a VCN Network (instead of macro + // cellular, etc) + if (wifiInfo == null && subId == INVALID_SUBSCRIPTION_ID) { + return null; + } + + // Prevent further forwarding by redacting everything in future parcels from + // this VcnTransportInfo + return new VcnTransportInfo(wifiInfo, subId, REDACT_ALL); } public VcnTransportInfo[] newArray(int size) { diff --git a/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java index 690e4e76ea5f..4bc5b49aa207 100644 --- a/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java +++ b/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java @@ -16,7 +16,6 @@ package android.net.vcn.persistablebundleutils; import android.annotation.NonNull; -import android.net.TunnelConnectionParams; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams; @@ -25,7 +24,7 @@ import android.os.PersistableBundle; import java.util.Objects; /** - * Utility class to convert TunnelConnectionParams to/from PersistableBundle + * Utility class to convert Tunnel Connection Params to/from PersistableBundle * * @hide */ @@ -34,30 +33,28 @@ public final class TunnelConnectionParamsUtils { private static final String PARAMS_TYPE_IKE = "IKE"; - /** Serializes an TunnelConnectionParams to a PersistableBundle. */ + /** Serializes an IkeTunnelConnectionParams to a PersistableBundle. */ @NonNull - public static PersistableBundle toPersistableBundle(@NonNull TunnelConnectionParams params) { + public static PersistableBundle toPersistableBundle(@NonNull IkeTunnelConnectionParams params) { final PersistableBundle result = new PersistableBundle(); - if (params instanceof IkeTunnelConnectionParams) { - result.putPersistableBundle( - PARAMS_TYPE_IKE, - IkeTunnelConnectionParamsUtils.serializeIkeParams( - (IkeTunnelConnectionParams) params)); - return result; - } else { - throw new UnsupportedOperationException("Invalid TunnelConnectionParams type"); - } + result.putPersistableBundle( + PARAMS_TYPE_IKE, + IkeTunnelConnectionParamsUtils.serializeIkeParams( + (IkeTunnelConnectionParams) params)); + return result; } - /** Constructs an TunnelConnectionParams by deserializing a PersistableBundle. */ + /** Constructs an IkeTunnelConnectionParams by deserializing a PersistableBundle. */ @NonNull - public static TunnelConnectionParams fromPersistableBundle(@NonNull PersistableBundle in) { + public static IkeTunnelConnectionParams fromPersistableBundle(@NonNull PersistableBundle in) { Objects.requireNonNull(in, "PersistableBundle was null"); if (in.keySet().size() != EXPECTED_BUNDLE_KEY_CNT) { throw new IllegalArgumentException( - "Expect PersistableBundle to have one element but found: " + in.keySet()); + String.format( + "Expect PersistableBundle to have %d element but found: %d", + EXPECTED_BUNDLE_KEY_CNT, in.keySet())); } if (in.get(PARAMS_TYPE_IKE) != null) { @@ -66,7 +63,7 @@ public final class TunnelConnectionParamsUtils { } throw new IllegalArgumentException( - "Invalid TunnelConnectionParams type " + in.keySet().iterator().next()); + "Invalid Tunnel Connection Params type " + in.keySet().iterator().next()); } private static final class IkeTunnelConnectionParamsUtils { diff --git a/core/java/android/nfc/NfcControllerAlwaysOnListener.java b/core/java/android/nfc/NfcControllerAlwaysOnListener.java index 96707bb432db..6ae58fd38cbe 100644 --- a/core/java/android/nfc/NfcControllerAlwaysOnListener.java +++ b/core/java/android/nfc/NfcControllerAlwaysOnListener.java @@ -52,6 +52,14 @@ public class NfcControllerAlwaysOnListener extends INfcControllerAlwaysOnListene */ public void register(@NonNull Executor executor, @NonNull ControllerAlwaysOnListener listener) { + try { + if (!mAdapter.isControllerAlwaysOnSupported()) { + return; + } + } catch (RemoteException e) { + Log.w(TAG, "Failed to register"); + return; + } synchronized (this) { if (mListenerMap.containsKey(listener)) { return; @@ -75,6 +83,14 @@ public class NfcControllerAlwaysOnListener extends INfcControllerAlwaysOnListene * @param listener user implementation of the {@link ControllerAlwaysOnListener} */ public void unregister(@NonNull ControllerAlwaysOnListener listener) { + try { + if (!mAdapter.isControllerAlwaysOnSupported()) { + return; + } + } catch (RemoteException e) { + Log.w(TAG, "Failed to unregister"); + return; + } synchronized (this) { if (!mListenerMap.containsKey(listener)) { return; diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java index ba63ba4521df..32ca92cc97b0 100644 --- a/core/java/android/os/BatteryConsumer.java +++ b/core/java/android/os/BatteryConsumer.java @@ -85,54 +85,6 @@ public abstract class BatteryConsumer { public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999; /** - * Time usage component, describing the particular part of the system - * that was used for the corresponding amount of time. - * - * @hide - */ - @IntDef(prefix = {"TIME_COMPONENT_"}, value = { - TIME_COMPONENT_SCREEN, - TIME_COMPONENT_CPU, - TIME_COMPONENT_CPU_FOREGROUND, - TIME_COMPONENT_BLUETOOTH, - TIME_COMPONENT_CAMERA, - TIME_COMPONENT_FLASHLIGHT, - TIME_COMPONENT_MOBILE_RADIO, - TIME_COMPONENT_SENSORS, - TIME_COMPONENT_GNSS, - TIME_COMPONENT_WIFI, - TIME_COMPONENT_WAKELOCK, - TIME_COMPONENT_MEMORY, - TIME_COMPONENT_PHONE, - TIME_COMPONENT_IDLE, - }) - @Retention(RetentionPolicy.SOURCE) - public static @interface TimeComponent { - } - - public static final int TIME_COMPONENT_SCREEN = 0; - public static final int TIME_COMPONENT_CPU = 1; - public static final int TIME_COMPONENT_CPU_FOREGROUND = 2; - public static final int TIME_COMPONENT_BLUETOOTH = 3; - public static final int TIME_COMPONENT_CAMERA = 4; - public static final int TIME_COMPONENT_AUDIO = 5; - public static final int TIME_COMPONENT_VIDEO = 6; - public static final int TIME_COMPONENT_FLASHLIGHT = 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_MEMORY = 13; - public static final int TIME_COMPONENT_PHONE = 14; - public static final int TIME_COMPONENT_IDLE = 15; - - public static final int TIME_COMPONENT_COUNT = 16; - - public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000; - public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999; - - /** * Identifiers of models used for power estimation. * * @hide @@ -166,7 +118,7 @@ public abstract class BatteryConsumer { * Total power consumed by this consumer, in mAh. */ public double getConsumedPower() { - return mPowerComponents.getTotalConsumedPower(); + return mPowerComponents.getConsumedPower(); } /** @@ -221,11 +173,11 @@ public abstract class BatteryConsumer { * Returns the amount of time since BatteryStats reset used by the specified component, e.g. * CPU, WiFi etc. * - * @param componentId The ID of the time component, e.g. - * {@link UidBatteryConsumer#TIME_COMPONENT_CPU}. + * @param componentId The ID of the power component, e.g. + * {@link UidBatteryConsumer#POWER_COMPONENT_CPU}. * @return Amount of time in milliseconds. */ - public long getUsageDurationMillis(@TimeComponent int componentId) { + public long getUsageDurationMillis(@PowerComponent int componentId) { return mPowerComponents.getUsageDurationMillis(componentId); } @@ -248,9 +200,9 @@ public abstract class BatteryConsumer { final PowerComponents.Builder mPowerComponentsBuilder; public BaseBuilder(@NonNull String[] customPowerComponentNames, - int customTimeComponentCount, boolean includePowerModels) { + boolean includePowerModels) { mPowerComponentsBuilder = new PowerComponents.Builder(customPowerComponentNames, - customTimeComponentCount, includePowerModels); + includePowerModels); } /** @@ -296,13 +248,13 @@ public abstract class BatteryConsumer { /** * Sets the amount of time used by the specified component, e.g. CPU, WiFi etc. * - * @param componentId The ID of the time component, e.g. - * {@link UidBatteryConsumer#TIME_COMPONENT_CPU}. + * @param componentId The ID of the power component, e.g. + * {@link UidBatteryConsumer#POWER_COMPONENT_CPU}. * @param componentUsageTimeMillis Amount of time in microseconds. */ @SuppressWarnings("unchecked") @NonNull - public T setUsageDurationMillis(@UidBatteryConsumer.TimeComponent int componentId, + public T setUsageDurationMillis(@UidBatteryConsumer.PowerComponent int componentId, long componentUsageTimeMillis) { mPowerComponentsBuilder.setUsageDurationMillis(componentId, componentUsageTimeMillis); return (T) this; diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java index 8ea59ce37018..efdef62d98ff 100644 --- a/core/java/android/os/BatteryUsageStats.java +++ b/core/java/android/os/BatteryUsageStats.java @@ -292,7 +292,6 @@ public final class BatteryUsageStats implements Parcelable { public static final class Builder { @NonNull private final String[] mCustomPowerComponentNames; - private final int mCustomTimeComponentCount; private final boolean mIncludePowerModels; private long mStatsStartTimestampMs; private int mDischargePercentage; @@ -309,14 +308,12 @@ public final class BatteryUsageStats implements Parcelable { private Parcel mHistoryBuffer; private List<BatteryStats.HistoryTag> mHistoryTagPool; - public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount) { - this(customPowerComponentNames, customTimeComponentCount, false); + public Builder(@NonNull String[] customPowerComponentNames) { + this(customPowerComponentNames, false); } - public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount, - boolean includePowerModels) { + public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels) { mCustomPowerComponentNames = customPowerComponentNames; - mCustomTimeComponentCount = customTimeComponentCount; mIncludePowerModels = includePowerModels; } @@ -399,7 +396,7 @@ public final class BatteryUsageStats implements Parcelable { UidBatteryConsumer.Builder builder = mUidBatteryConsumerBuilders.get(uid); if (builder == null) { builder = new UidBatteryConsumer.Builder(mCustomPowerComponentNames, - mCustomTimeComponentCount, mIncludePowerModels, batteryStatsUid); + mIncludePowerModels, batteryStatsUid); mUidBatteryConsumerBuilders.put(uid, builder); } return builder; @@ -415,7 +412,7 @@ public final class BatteryUsageStats implements Parcelable { SystemBatteryConsumer.Builder builder = mSystemBatteryConsumerBuilders.get(drainType); if (builder == null) { builder = new SystemBatteryConsumer.Builder(mCustomPowerComponentNames, - mCustomTimeComponentCount, mIncludePowerModels, drainType); + mIncludePowerModels, drainType); mSystemBatteryConsumerBuilders.put(drainType, builder); } return builder; @@ -430,7 +427,7 @@ public final class BatteryUsageStats implements Parcelable { UserBatteryConsumer.Builder builder = mUserBatteryConsumerBuilders.get(userId); if (builder == null) { builder = new UserBatteryConsumer.Builder(mCustomPowerComponentNames, - mCustomTimeComponentCount, mIncludePowerModels, userId); + mIncludePowerModels, userId); mUserBatteryConsumerBuilders.put(userId, builder); } return builder; diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index c0847872a45a..0c9ad1b17a7e 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -31,6 +31,7 @@ import static android.system.OsConstants.S_ISLNK; import static android.system.OsConstants.S_ISREG; import static android.system.OsConstants.S_IWOTH; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SuppressLint; import android.annotation.SystemApi; @@ -63,6 +64,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.io.UncheckedIOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.net.DatagramSocket; import java.net.Socket; import java.nio.ByteOrder; @@ -110,6 +113,20 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { private final CloseGuard mGuard = CloseGuard.get(); + /** @hide */ + @IntDef(prefix = {"MODE_"}, value = { + MODE_WORLD_READABLE, + MODE_WORLD_WRITEABLE, + MODE_READ_ONLY, + MODE_WRITE_ONLY, + MODE_READ_WRITE, + MODE_CREATE, + MODE_TRUNCATE, + MODE_APPEND, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Mode { } + /** * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and * this file doesn't already exist, then create the file with permissions @@ -227,7 +244,8 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * be opened with the requested mode. * @see #parseMode(String) */ - public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException { + public static ParcelFileDescriptor open(File file, @Mode int mode) + throws FileNotFoundException { final FileDescriptor fd = openInternal(file, mode); if (fd == null) return null; @@ -259,7 +277,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { // We can't accept a generic Executor here, since we need to use // MessageQueue.addOnFileDescriptorEventListener() @SuppressLint("ExecutorRegistration") - public static ParcelFileDescriptor open(File file, int mode, Handler handler, + public static ParcelFileDescriptor open(File file, @Mode int mode, Handler handler, final OnCloseListener listener) throws IOException { if (handler == null) { throw new IllegalArgumentException("Handler must not be null"); @@ -330,7 +348,8 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { return pfd; } - private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException { + private static FileDescriptor openInternal(File file, @Mode int mode) + throws FileNotFoundException { final int flags = FileUtils.translateModePfdToPosix(mode) | ifAtLeastQ(O_CLOEXEC); int realMode = S_IRWXU | S_IRWXG; @@ -623,15 +642,36 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } /** - * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use - * with {@link #open}. + * Converts a string representing a file mode, such as "rw", into a bitmask + * suitable for use with {@link #open}. * <p> - * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw" - * or "rwt". + * The argument must define at least one of the following base access modes: + * <ul> + * <li>"r" indicates the file should be opened in read-only mode, equivalent + * to {@link OsConstants#O_RDONLY}. + * <li>"w" indicates the file should be opened in write-only mode, + * equivalent to {@link OsConstants#O_WRONLY}. + * <li>"rw" indicates the file should be opened in read-write mode, + * equivalent to {@link OsConstants#O_RDWR}. + * </ul> + * In addition to a base access mode, the following additional modes may + * requested: + * <ul> + * <li>"a" indicates the file should be opened in append mode, equivalent to + * {@link OsConstants#O_APPEND}. Before each write, the file offset is + * positioned at the end of the file. + * <li>"t" indicates the file should be opened in truncate mode, equivalent + * to {@link OsConstants#O_TRUNC}. If the file already exists and is a + * regular file and is opened for writing, it will be truncated to length 0. + * </ul> + * + * @param mode The string representation of the file mode. Can be "r", "w", + * "wt", "wa", "rw" or "rwt". * @return A bitmask representing the given file mode. - * @throws IllegalArgumentException if the given string does not match a known file mode. + * @throws IllegalArgumentException if the given string does not match a + * known file mode. */ - public static int parseMode(String mode) { + public static @Mode int parseMode(String mode) { return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode)); } diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java index a0a41f4d6630..47a2edccc640 100644 --- a/core/java/android/os/PowerComponents.java +++ b/core/java/android/os/PowerComponents.java @@ -26,12 +26,10 @@ import android.annotation.NonNull; class PowerComponents { private static final int CUSTOM_POWER_COMPONENT_OFFSET = BatteryConsumer.POWER_COMPONENT_COUNT - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID; - private static final int CUSTOM_TIME_COMPONENT_OFFSET = BatteryConsumer.TIME_COMPONENT_COUNT - - BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID; - private final double mTotalConsumedPowerMah; + private final double mConsumedPowerMah; private final double[] mPowerComponentsMah; - private final long[] mTimeComponentsMs; + private final long[] mUsageDurationsMs; private final int mCustomPowerComponentCount; private final byte[] mPowerModels; // Not written to Parcel and must be explicitly restored during the parent object's unparceling @@ -41,16 +39,16 @@ class PowerComponents { mCustomPowerComponentNames = builder.mCustomPowerComponentNames; mCustomPowerComponentCount = mCustomPowerComponentNames.length; mPowerComponentsMah = builder.mPowerComponentsMah; - mTimeComponentsMs = builder.mTimeComponentsMs; - mTotalConsumedPowerMah = builder.getTotalPower(); + mUsageDurationsMs = builder.mUsageDurationsMs; + mConsumedPowerMah = builder.getTotalPower(); mPowerModels = builder.mPowerModels; } PowerComponents(@NonNull Parcel source) { - mTotalConsumedPowerMah = source.readDouble(); + mConsumedPowerMah = source.readDouble(); mCustomPowerComponentCount = source.readInt(); mPowerComponentsMah = source.createDoubleArray(); - mTimeComponentsMs = source.createLongArray(); + mUsageDurationsMs = source.createLongArray(); if (source.readBoolean()) { mPowerModels = new byte[BatteryConsumer.POWER_COMPONENT_COUNT]; source.readByteArray(mPowerModels); @@ -61,10 +59,10 @@ class PowerComponents { /** Writes contents to Parcel */ void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeDouble(mTotalConsumedPowerMah); + dest.writeDouble(mConsumedPowerMah); dest.writeInt(mCustomPowerComponentCount); dest.writeDoubleArray(mPowerComponentsMah); - dest.writeLongArray(mTimeComponentsMs); + dest.writeLongArray(mUsageDurationsMs); if (mPowerModels != null) { dest.writeBoolean(true); dest.writeByteArray(mPowerModels); @@ -76,8 +74,8 @@ class PowerComponents { /** * Total power consumed by this consumer, in mAh. */ - public double getTotalConsumedPower() { - return mTotalConsumedPowerMah; + public double getConsumedPower() { + return mConsumedPowerMah; } /** @@ -152,17 +150,17 @@ class PowerComponents { /** * Returns the amount of time used by the specified component, e.g. CPU, WiFi etc. * - * @param componentId The ID of the time component, e.g. - * {@link BatteryConsumer#TIME_COMPONENT_CPU}. + * @param componentId The ID of the power component, e.g. + * {@link BatteryConsumer#POWER_COMPONENT_CPU}. * @return Amount of time in milliseconds. */ - public long getUsageDurationMillis(@BatteryConsumer.TimeComponent int componentId) { - if (componentId >= BatteryConsumer.TIME_COMPONENT_COUNT) { + public long getUsageDurationMillis(@BatteryConsumer.PowerComponent int componentId) { + if (componentId >= BatteryConsumer.POWER_COMPONENT_COUNT) { throw new IllegalArgumentException( - "Unsupported time component ID: " + componentId); + "Unsupported power component ID: " + componentId); } try { - return mTimeComponentsMs[componentId]; + return mUsageDurationsMs[componentId]; } catch (ArrayIndexOutOfBoundsException e) { throw new IllegalArgumentException("Unsupported power component ID: " + componentId); } @@ -175,15 +173,15 @@ class PowerComponents { * @return Amount of time in milliseconds. */ public long getUsageDurationForCustomComponentMillis(int componentId) { - if (componentId < BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID) { + if (componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) { throw new IllegalArgumentException( - "Unsupported custom time component ID: " + componentId); + "Unsupported custom power component ID: " + componentId); } try { - return mTimeComponentsMs[CUSTOM_TIME_COMPONENT_OFFSET + componentId]; + return mUsageDurationsMs[CUSTOM_POWER_COMPONENT_OFFSET + componentId]; } catch (ArrayIndexOutOfBoundsException e) { throw new IllegalArgumentException( - "Unsupported custom time component ID: " + componentId); + "Unsupported custom power component ID: " + componentId); } } @@ -192,13 +190,13 @@ class PowerComponents { } /** - * Returns the largest usage duration among all time components. + * Returns the largest usage duration among all power components. */ public long getMaxComponentUsageDurationMillis() { long max = 0; - for (int i = mTimeComponentsMs.length - 1; i >= 0; i--) { - if (mTimeComponentsMs[i] > max) { - max = mTimeComponentsMs[i]; + for (int i = mUsageDurationsMs.length - 1; i >= 0; i--) { + if (mUsageDurationsMs[i] > max) { + max = mUsageDurationsMs[i]; } } return max; @@ -210,17 +208,15 @@ class PowerComponents { static final class Builder { private final double[] mPowerComponentsMah; private final String[] mCustomPowerComponentNames; - private final long[] mTimeComponentsMs; + private final long[] mUsageDurationsMs; private final byte[] mPowerModels; - Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount, - boolean includePowerModels) { + Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels) { mCustomPowerComponentNames = customPowerComponentNames; int powerComponentCount = BatteryConsumer.POWER_COMPONENT_COUNT + mCustomPowerComponentNames.length; mPowerComponentsMah = new double[powerComponentCount]; - mTimeComponentsMs = - new long[BatteryConsumer.TIME_COMPONENT_COUNT + customTimeComponentCount]; + mUsageDurationsMs = new long[powerComponentCount]; if (includePowerModels) { mPowerModels = new byte[BatteryConsumer.POWER_COMPONENT_COUNT]; } else { @@ -281,22 +277,22 @@ class PowerComponents { /** * Sets the amount of time used by the specified component, e.g. CPU, WiFi etc. * - * @param componentId The ID of the time component, e.g. - * {@link BatteryConsumer#TIME_COMPONENT_CPU}. + * @param componentId The ID of the power component, e.g. + * {@link BatteryConsumer#POWER_COMPONENT_CPU}. * @param componentUsageDurationMillis Amount of time in milliseconds. */ @NonNull - public Builder setUsageDurationMillis(@BatteryConsumer.TimeComponent int componentId, + public Builder setUsageDurationMillis(@BatteryConsumer.PowerComponent int componentId, long componentUsageDurationMillis) { - if (componentId >= BatteryConsumer.TIME_COMPONENT_COUNT) { + if (componentId >= BatteryConsumer.POWER_COMPONENT_COUNT) { throw new IllegalArgumentException( - "Unsupported time component ID: " + componentId); + "Unsupported power component ID: " + componentId); } try { - mTimeComponentsMs[componentId] = componentUsageDurationMillis; + mUsageDurationsMs[componentId] = componentUsageDurationMillis; } catch (ArrayIndexOutOfBoundsException e) { throw new IllegalArgumentException( - "Unsupported time component ID: " + componentId); + "Unsupported power component ID: " + componentId); } return this; } @@ -310,16 +306,16 @@ class PowerComponents { @NonNull public Builder setUsageDurationForCustomComponentMillis(int componentId, long componentUsageDurationMillis) { - if (componentId < BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID) { + if (componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) { throw new IllegalArgumentException( - "Unsupported custom time component ID: " + componentId); + "Unsupported custom power component ID: " + componentId); } try { - mTimeComponentsMs[CUSTOM_TIME_COMPONENT_OFFSET + componentId] = + mUsageDurationsMs[CUSTOM_POWER_COMPONENT_OFFSET + componentId] = componentUsageDurationMillis; } catch (ArrayIndexOutOfBoundsException e) { throw new IllegalArgumentException( - "Unsupported custom time component ID: " + componentId); + "Unsupported custom power component ID: " + componentId); } return this; } @@ -328,8 +324,8 @@ class PowerComponents { for (int i = mPowerComponentsMah.length - 1; i >= 0; i--) { mPowerComponentsMah[i] += other.mPowerComponentsMah[i]; } - for (int i = mTimeComponentsMs.length - 1; i >= 0; i--) { - mTimeComponentsMs[i] += other.mTimeComponentsMs[i]; + for (int i = mUsageDurationsMs.length - 1; i >= 0; i--) { + mUsageDurationsMs[i] += other.mUsageDurationsMs[i]; } } diff --git a/core/java/android/os/SystemBatteryConsumer.java b/core/java/android/os/SystemBatteryConsumer.java index 1327978ad0ba..7618339260bd 100644 --- a/core/java/android/os/SystemBatteryConsumer.java +++ b/core/java/android/os/SystemBatteryConsumer.java @@ -147,9 +147,9 @@ public class SystemBatteryConsumer extends BatteryConsumer implements Parcelable private double mPowerConsumedByAppsMah; private List<UidBatteryConsumer.Builder> mUidBatteryConsumers; - Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount, + Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels, @DrainType int drainType) { - super(customPowerComponentNames, customTimeComponentCount, includePowerModels); + super(customPowerComponentNames, includePowerModels); mDrainType = drainType; } diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java index 92e960344f3e..b1fb570b4395 100644 --- a/core/java/android/os/UidBatteryConsumer.java +++ b/core/java/android/os/UidBatteryConsumer.java @@ -139,9 +139,9 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela public long mTimeInBackgroundMs; private boolean mExcludeFromBatteryUsageStats; - public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount, + public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels, @NonNull BatteryStats.Uid batteryStatsUid) { - super(customPowerComponentNames, customTimeComponentCount, includePowerModels); + super(customPowerComponentNames, includePowerModels); mBatteryStatsUid = batteryStatsUid; mUid = batteryStatsUid.getUid(); } diff --git a/core/java/android/os/UserBatteryConsumer.java b/core/java/android/os/UserBatteryConsumer.java index de0a707fb656..d0d0d38a75d2 100644 --- a/core/java/android/os/UserBatteryConsumer.java +++ b/core/java/android/os/UserBatteryConsumer.java @@ -77,9 +77,9 @@ public class UserBatteryConsumer extends BatteryConsumer implements Parcelable { private final int mUserId; private List<UidBatteryConsumer.Builder> mUidBatteryConsumers; - Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount, - boolean includePowerModels, int userId) { - super(customPowerComponentNames, customTimeComponentCount, includePowerModels); + Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels, + int userId) { + super(customPowerComponentNames, includePowerModels); mUserId = userId; } diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index b3502f38dd53..95962c82a611 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -554,9 +554,12 @@ public abstract class Vibrator { /** * Query the estimated durations of the given primitives. * - * The returned array will be the same length as the query array and the value at a given index - * will contain the duration in milliseconds of the effect at the same index in the querying - * array. + * <p>The returned array will be the same length as the query array and the value at a given + * index will contain the duration in milliseconds of the effect at the same index in the + * querying array. + * + * <p>The duration will be positive for primitives that are supported and zero for the + * unsupported ones, in correspondence with {@link #arePrimitivesSupported(int...)}. * * @param primitiveIds Which primitives to query for. * @return The duration of each primitive, with zeroes for primitives that are not supported. diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java index d73469ca7e8e..597df0811e20 100644 --- a/core/java/android/os/VibratorInfo.java +++ b/core/java/android/os/VibratorInfo.java @@ -260,7 +260,7 @@ public class VibratorInfo implements Parcelable { */ public int getPrimitiveDuration( @VibrationEffect.Composition.PrimitiveType int primitiveId) { - return mSupportedPrimitives.get(primitiveId); + return mSupportedPrimitives != null ? mSupportedPrimitives.get(primitiveId) : 0; } /** diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl index fe3197a98bae..c68f878b3b74 100644 --- a/core/java/android/os/incremental/IIncrementalService.aidl +++ b/core/java/android/os/incremental/IIncrementalService.aidl @@ -167,6 +167,27 @@ interface IIncrementalService { */ const @utf8InCpp String METRICS_MILLIS_SINCE_OLDEST_PENDING_READ = "millisSinceOldestPendingRead"; /** + * Metrics key for whether read logs are enabled. The value is a boolean. + */ + const @utf8InCpp String METRICS_READ_LOGS_ENABLED = "readLogsEnabled"; + /** + * Metrics key for the storage health status. The value is an int. + */ + const @utf8InCpp String METRICS_STORAGE_HEALTH_STATUS_CODE = "storageHealthStatusCode"; + /** + * Metrics key for the data loader status. The value is an int. + */ + const @utf8InCpp String METRICS_DATA_LOADER_STATUS_CODE = "dataLoaderStatusCode"; + /** + * Metrics key for duration since last data loader binding attempt. The value is a long. + */ + const @utf8InCpp String METRICS_MILLIS_SINCE_LAST_DATA_LOADER_BIND = "millisSinceLastDataLoaderBind"; + /** + * Metrics key for delay in milliseconds to retry data loader binding. The value is a long. + */ + const @utf8InCpp String METRICS_DATA_LOADER_BIND_DELAY_MILLIS = "dataLoaderBindDelayMillis"; + + /** * Return a bundle containing the requested metrics keys and their values. */ PersistableBundle getMetrics(int storageId); diff --git a/core/java/android/os/incremental/IncrementalMetrics.java b/core/java/android/os/incremental/IncrementalMetrics.java index 44dea1be50f0..98eb4312d7bf 100644 --- a/core/java/android/os/incremental/IncrementalMetrics.java +++ b/core/java/android/os/incremental/IncrementalMetrics.java @@ -36,4 +36,39 @@ public class IncrementalMetrics { public long getMillisSinceOldestPendingRead() { return mData.getLong(IIncrementalService.METRICS_MILLIS_SINCE_OLDEST_PENDING_READ, -1); } + + /** + * @return Whether read logs are enabled + */ + public boolean getReadLogsEnabled() { + return mData.getBoolean(IIncrementalService.METRICS_READ_LOGS_ENABLED, false); + } + + /** + * @return storage health status code. @see android.os.incremental.IStorageHealthListener + */ + public int getStorageHealthStatusCode() { + return mData.getInt(IIncrementalService.METRICS_STORAGE_HEALTH_STATUS_CODE, -1); + } + + /** + * @return data loader status code. @see android.content.pm.IDataLoaderStatusListener + */ + public int getDataLoaderStatusCode() { + return mData.getInt(IIncrementalService.METRICS_DATA_LOADER_STATUS_CODE, -1); + } + + /** + * @return duration since last data loader binding attempt + */ + public long getMillisSinceLastDataLoaderBind() { + return mData.getLong(IIncrementalService.METRICS_MILLIS_SINCE_LAST_DATA_LOADER_BIND, -1); + } + + /** + * @return delay in milliseconds to retry data loader binding + */ + public long getDataLoaderBindDelayMillis() { + return mData.getLong(IIncrementalService.METRICS_DATA_LOADER_BIND_DELAY_MILLIS, -1); + } } diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java index a56e821889e0..ca132e975e85 100644 --- a/core/java/android/permission/PermissionControllerManager.java +++ b/core/java/android/permission/PermissionControllerManager.java @@ -725,12 +725,14 @@ public final class PermissionControllerManager { * Get the platform permissions which belong to a particular permission group. * * @param permissionGroupName The permission group whose permissions are desired + * @param executor Executor on which to invoke the callback * @param callback A callback which will receive a list of the platform permissions in the * group, or empty if the group is not a valid platform group, or there * was an exception. */ @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING) public void getPlatformPermissionsForGroup(@NonNull String permissionGroupName, + @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<List<String>> callback) { enforceSomePermissionsGrantedToSelf( Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING); @@ -738,14 +740,19 @@ public final class PermissionControllerManager { AndroidFuture<List<String>> future = new AndroidFuture<>(); service.getPlatformPermissionsForGroup(permissionGroupName, future); return future; - }).whenComplete((result, err) -> { - if (err != null) { - Log.e(TAG, "Failed to get permissions of " + permissionGroupName, err); - callback.accept(new ArrayList<>()); - } else { - callback.accept(result); + }).whenCompleteAsync((result, err) -> { + final long token = Binder.clearCallingIdentity(); + try { + if (err != null) { + Log.e(TAG, "Failed to get permissions of " + permissionGroupName, err); + callback.accept(new ArrayList<>()); + } else { + callback.accept(result); + } + } finally { + Binder.restoreCallingIdentity(token); } - }); + }, executor); } /** @@ -753,26 +760,32 @@ public final class PermissionControllerManager { * permission. * * @param permissionName The permission name whose group is desired + * @param executor Executor on which to invoke the callback * @param callback A callback which will receive the name of the permission group this * permission belongs to, or null if it has no group, is not a platform * permission, or there was an exception. */ @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING) public void getGroupOfPlatformPermission(@NonNull String permissionName, - @NonNull Consumer<String> callback) { + @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<String> callback) { enforceSomePermissionsGrantedToSelf( Manifest.permission.GET_RUNTIME_PERMISSION_GROUP_MAPPING); mRemoteService.postAsync(service -> { AndroidFuture<String> future = new AndroidFuture<>(); service.getGroupOfPlatformPermission(permissionName, future); return future; - }).whenComplete((result, err) -> { - if (err != null) { - Log.e(TAG, "Failed to get group of " + permissionName, err); - callback.accept(null); - } else { - callback.accept(result); + }).whenCompleteAsync((result, err) -> { + final long token = Binder.clearCallingIdentity(); + try { + if (err != null) { + Log.e(TAG, "Failed to get group of " + permissionName, err); + callback.accept(null); + } else { + callback.accept(result); + } + } finally { + Binder.restoreCallingIdentity(token); } - }); + }, executor); } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index f8991ce1e97b..c8e5e4275e74 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -83,6 +83,7 @@ import android.util.ArraySet; import android.util.Log; import android.util.MemoryIntArray; import android.view.Display; +import android.view.Window; import android.view.WindowManager.LayoutParams; import com.android.internal.annotations.GuardedBy; @@ -6606,7 +6607,6 @@ public final class Settings { * * @hide */ - @Readable public static final String ALWAYS_ON_VPN_APP = "always_on_vpn_app"; /** @@ -8515,6 +8515,12 @@ public final class Settings { "swipe_bottom_to_notification_enabled"; /** + * Controls whether One-Handed mode is currently activated. + * @hide + */ + public static final String ONE_HANDED_MODE_ACTIVATED = "one_handed_mode_activated"; + + /** * For user preference if One-Handed Mode enabled. * @hide */ @@ -13372,6 +13378,19 @@ public final class Settings { public static final String WINDOW_ANIMATION_SCALE = "window_animation_scale"; /** + * Setting to disable cross-window blurs. This includes window blur behind, (see + * {@link LayoutParams#setBlurBehindRadius}) and window background blur (see + * {@link Window#setBackgroundBlurRadius}). + * + * The value is a boolean (1 or 0). + * @hide + */ + @TestApi + @Readable + @SuppressLint("NoSettingsProvider") + public static final String DISABLE_WINDOW_BLURS = "disable_window_blurs"; + + /** * Scaling factor for activity transition animations. * * The value is a float. Setting to 0.0f will disable window animations. diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 5a89cdf1d340..0b11aeb1ed65 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -66,9 +66,6 @@ public final class KeymasterDefs { public static final int KM_TAG_CALLER_NONCE = Tag.CALLER_NONCE; // KM_BOOL | 7; public static final int KM_TAG_MIN_MAC_LENGTH = Tag.MIN_MAC_LENGTH; // KM_UINT | 8; - public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS = - Tag.BLOB_USAGE_REQUIREMENTS; // KM_ENUM | 705; - public static final int KM_TAG_RSA_PUBLIC_EXPONENT = Tag.RSA_PUBLIC_EXPONENT; // KM_ULONG | 200; public static final int KM_TAG_INCLUDE_UNIQUE_ID = Tag.INCLUDE_UNIQUE_ID; // KM_BOOL | 202; diff --git a/core/java/android/service/displayhash/DisplayHashParams.java b/core/java/android/service/displayhash/DisplayHashParams.java index 2ec9d5d11101..123c209519b6 100644 --- a/core/java/android/service/displayhash/DisplayHashParams.java +++ b/core/java/android/service/displayhash/DisplayHashParams.java @@ -48,7 +48,7 @@ public final class DisplayHashParams implements Parcelable { /** * Whether the content will be captured in grayscale or color. */ - private final boolean mUseGrayscale; + private final boolean mGrayscaleBuffer; /** * A builder for {@link DisplayHashParams} @@ -56,7 +56,7 @@ public final class DisplayHashParams implements Parcelable { public static final class Builder { @Nullable private Size mBufferSize; - private boolean mUseGrayscale; + private boolean mGrayscaleBuffer; /** * Creates a new Builder. @@ -77,15 +77,15 @@ public final class DisplayHashParams implements Parcelable { * Whether the content will be captured in grayscale or color. */ @NonNull - public Builder setUseGrayscale(boolean useGrayscale) { - mUseGrayscale = useGrayscale; + public Builder setGrayscaleBuffer(boolean grayscaleBuffer) { + mGrayscaleBuffer = grayscaleBuffer; return this; } /** Builds the instance. This builder should not be touched after calling this! */ @NonNull public DisplayHashParams build() { - return new DisplayHashParams(mBufferSize, mUseGrayscale); + return new DisplayHashParams(mBufferSize, mGrayscaleBuffer); } } @@ -112,16 +112,16 @@ public final class DisplayHashParams implements Parcelable { * buffer given to the {@link DisplayHashingService#onGenerateDisplayHash(byte[], * HardwareBuffer, Rect, String, DisplayHashResultCallback)} will be stretched based on the * value set here. If {@code null}, the buffer size will not be changed. - * @param useGrayscale + * @param grayscaleBuffer * Whether the content will be captured in grayscale or color. * @hide */ @DataClass.Generated.Member public DisplayHashParams( @Nullable Size bufferSize, - boolean useGrayscale) { + boolean grayscaleBuffer) { this.mBufferSize = bufferSize; - this.mUseGrayscale = useGrayscale; + this.mGrayscaleBuffer = grayscaleBuffer; // onConstructed(); // You can define this method to get a callback } @@ -141,8 +141,8 @@ public final class DisplayHashParams implements Parcelable { * Whether the content will be captured in grayscale or color. */ @DataClass.Generated.Member - public boolean isUseGrayscale() { - return mUseGrayscale; + public boolean isGrayscaleBuffer() { + return mGrayscaleBuffer; } @Override @@ -153,7 +153,7 @@ public final class DisplayHashParams implements Parcelable { return "DisplayHashParams { " + "bufferSize = " + mBufferSize + ", " + - "useGrayscale = " + mUseGrayscale + + "grayscaleBuffer = " + mGrayscaleBuffer + " }"; } @@ -164,7 +164,7 @@ public final class DisplayHashParams implements Parcelable { // void parcelFieldName(Parcel dest, int flags) { ... } byte flg = 0; - if (mUseGrayscale) flg |= 0x2; + if (mGrayscaleBuffer) flg |= 0x2; if (mBufferSize != null) flg |= 0x1; dest.writeByte(flg); if (mBufferSize != null) dest.writeSize(mBufferSize); @@ -182,11 +182,11 @@ public final class DisplayHashParams implements Parcelable { // static FieldType unparcelFieldName(Parcel in) { ... } byte flg = in.readByte(); - boolean useGrayscale = (flg & 0x2) != 0; + boolean grayscaleBuffer = (flg & 0x2) != 0; Size bufferSize = (flg & 0x1) == 0 ? null : (Size) in.readSize(); this.mBufferSize = bufferSize; - this.mUseGrayscale = useGrayscale; + this.mGrayscaleBuffer = grayscaleBuffer; // onConstructed(); // You can define this method to get a callback } @@ -206,10 +206,10 @@ public final class DisplayHashParams implements Parcelable { }; @DataClass.Generated( - time = 1618436855096L, + time = 1619638159453L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/service/displayhash/DisplayHashParams.java", - inputSignatures = "private final @android.annotation.Nullable android.util.Size mBufferSize\nprivate final boolean mUseGrayscale\nclass DisplayHashParams extends java.lang.Object implements [android.os.Parcelable]\nprivate @android.annotation.Nullable android.util.Size mBufferSize\nprivate boolean mUseGrayscale\npublic @android.annotation.NonNull android.service.displayhash.DisplayHashParams.Builder setBufferSize(int,int)\npublic @android.annotation.NonNull android.service.displayhash.DisplayHashParams.Builder setUseGrayscale(boolean)\npublic @android.annotation.NonNull android.service.displayhash.DisplayHashParams build()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genAidl=true, genToString=true, genParcelable=true, genHiddenConstructor=true)") + inputSignatures = "private final @android.annotation.Nullable android.util.Size mBufferSize\nprivate final boolean mGrayscaleBuffer\nclass DisplayHashParams extends java.lang.Object implements [android.os.Parcelable]\nprivate @android.annotation.Nullable android.util.Size mBufferSize\nprivate boolean mGrayscaleBuffer\npublic @android.annotation.NonNull android.service.displayhash.DisplayHashParams.Builder setBufferSize(int,int)\npublic @android.annotation.NonNull android.service.displayhash.DisplayHashParams.Builder setGrayscaleBuffer(boolean)\npublic @android.annotation.NonNull android.service.displayhash.DisplayHashParams build()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genAidl=true, genToString=true, genParcelable=true, genHiddenConstructor=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/service/rotationresolver/RotationResolverService.java b/core/java/android/service/rotationresolver/RotationResolverService.java index 604dd0ac8298..0932901edf50 100644 --- a/core/java/android/service/rotationresolver/RotationResolverService.java +++ b/core/java/android/service/rotationresolver/RotationResolverService.java @@ -136,9 +136,6 @@ public abstract class RotationResolverService extends Service { @MainThread private void resolveRotation(IRotationResolverCallback callback, RotationResolutionRequest request, ICancellationSignal transport) { - // TODO(b/175334753): The current behavior of preempted failures is based on the design we - // had in Smart OS exploration. We should revisit it once we have implemented the whole - // feature and tested on devices. if (mPendingCallback != null && (mCancellationSignal == null || !mCancellationSignal.isCanceled())) { reportFailures(callback, ROTATION_RESULT_FAILURE_PREEMPTED); diff --git a/core/java/android/service/search/SearchUiService.java b/core/java/android/service/search/SearchUiService.java index d0e41956523a..c04dd9cd20bc 100644 --- a/core/java/android/service/search/SearchUiService.java +++ b/core/java/android/service/search/SearchUiService.java @@ -45,6 +45,9 @@ import java.util.function.Consumer; * A service used to share the lifecycle of search UI (open, close, interaction) * and also to return search result on a query. * + * To understand the lifecycle of search session and how a query get issued, + * {@see SearchSession} + * * @hide */ @SystemApi @@ -71,6 +74,10 @@ public abstract class SearchUiService extends Service { @Override public void onCreateSearchSession(SearchContext context, SearchSessionId sessionId) { mHandler.sendMessage( + obtainMessage(SearchUiService::onSearchSessionCreated, + SearchUiService.this, context, sessionId)); + // to be removed + mHandler.sendMessage( obtainMessage(SearchUiService::onCreateSearchSession, SearchUiService.this, context, sessionId)); } @@ -119,11 +126,24 @@ public abstract class SearchUiService extends Service { /** * Creates a new search session. + * + * @deprecated this is method will be removed as soon as + * {@link #onSearchSessionCreated(SearchContext, SearchSessionId)} + * is adopted by the service. + * + * @removed */ + @Deprecated public void onCreateSearchSession(@NonNull SearchContext context, @NonNull SearchSessionId sessionId) {} /** + * A new search session is created. + */ + public void onSearchSessionCreated(@NonNull SearchContext context, + @NonNull SearchSessionId sessionId) {} + + /** * Called by the client to request search results using a query string. */ @MainThread @@ -132,7 +152,10 @@ public abstract class SearchUiService extends Service { @NonNull Consumer<List<SearchTarget>> callback); /** - * Called by a client to indicate an interaction (tap, long press, drag, etc) on target(s). + * Called by a client to indicate an interaction (tap, long press, drag, etc) on target(s) + * and lifecycle event on the search surface (e.g., visibility change). + * + * {@see SearchTargetEvent} */ @MainThread public abstract void onNotifyEvent(@NonNull SearchSessionId sessionId, diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 3c53e8f305ae..bacc6ec2227b 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -349,7 +349,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { private final HotwordDetectedResult mHotwordDetectedResult; private final ParcelFileDescriptor mAudioStream; - private EventPayload(boolean triggerAvailable, boolean captureAvailable, + EventPayload(boolean triggerAvailable, boolean captureAvailable, AudioFormat audioFormat, int captureSession, byte[] data) { this(triggerAvailable, captureAvailable, audioFormat, captureSession, data, null, null); diff --git a/core/java/android/service/voice/HotwordDetectedResult.java b/core/java/android/service/voice/HotwordDetectedResult.java index f5d796f92a4d..e50de1c30ba0 100644 --- a/core/java/android/service/voice/HotwordDetectedResult.java +++ b/core/java/android/service/voice/HotwordDetectedResult.java @@ -21,6 +21,7 @@ import static android.service.voice.HotwordDetector.CONFIDENCE_LEVEL_NONE; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.media.MediaSyncEvent; import android.os.Parcelable; import android.os.PersistableBundle; @@ -53,9 +54,17 @@ public final class HotwordDetectedResult implements Parcelable { } /** + * A {@code MediaSyncEvent} that allows the {@link HotwordDetector} to recapture the audio + * that contains the hotword trigger. This must be obtained using + * {@link android.media.AudioRecord#shareAudioHistory(String, long)}. + * <p> + * This can be {@code null} if reprocessing the hotword trigger isn't required. + */ + @Nullable + private MediaSyncEvent mMediaSyncEvent = null; + + /** * Byte offset in the audio stream when the trigger event happened. - * - * <p>If unset, the most recent bytes in the audio stream will be used. */ private final int mByteOffset; private static int defaultByteOffset() { @@ -84,7 +93,7 @@ public final class HotwordDetectedResult implements Parcelable { /** * Returns the maximum values of {@link #getScore} and {@link #getPersonalizedScore}. - * + * <p> * The float value should be calculated as {@code getScore() / getMaxScore()}. */ public static int getMaxScore() { @@ -159,6 +168,7 @@ public final class HotwordDetectedResult implements Parcelable { @DataClass.Generated.Member /* package-private */ HotwordDetectedResult( @HotwordDetector.HotwordConfidenceLevelValue int confidenceLevel, + @Nullable MediaSyncEvent mediaSyncEvent, int byteOffset, int score, int personalizedScore, @@ -167,6 +177,7 @@ public final class HotwordDetectedResult implements Parcelable { this.mConfidenceLevel = confidenceLevel; com.android.internal.util.AnnotationValidations.validate( HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel); + this.mMediaSyncEvent = mediaSyncEvent; this.mByteOffset = byteOffset; this.mScore = score; this.mPersonalizedScore = personalizedScore; @@ -187,9 +198,19 @@ public final class HotwordDetectedResult implements Parcelable { } /** + * A {@code MediaSyncEvent} that allows the {@link HotwordDetector} to recapture the audio + * that contains the hotword trigger. This must be obtained using + * {@link android.media.AudioRecord#shareAudioHistory(String, long)}. + * <p> + * This can be {@code null} if reprocessing the hotword trigger isn't required. + */ + @DataClass.Generated.Member + public @Nullable MediaSyncEvent getMediaSyncEvent() { + return mMediaSyncEvent; + } + + /** * Byte offset in the audio stream when the trigger event happened. - * - * <p>If unset, the most recent bytes in the audio stream will be used. */ @DataClass.Generated.Member public int getByteOffset() { @@ -237,6 +258,9 @@ public final class HotwordDetectedResult implements Parcelable { * * <p>The use of this method is discouraged, and support for it will be removed in future * versions of Android. + * + * <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents + * that can be used to communicate with other processes. */ @DataClass.Generated.Member public @NonNull PersistableBundle getExtras() { @@ -251,6 +275,7 @@ public final class HotwordDetectedResult implements Parcelable { return "HotwordDetectedResult { " + "confidenceLevel = " + mConfidenceLevel + ", " + + "mediaSyncEvent = " + mMediaSyncEvent + ", " + "byteOffset = " + mByteOffset + ", " + "score = " + mScore + ", " + "personalizedScore = " + mPersonalizedScore + ", " + @@ -273,6 +298,7 @@ public final class HotwordDetectedResult implements Parcelable { //noinspection PointlessBooleanExpression return true && mConfidenceLevel == that.mConfidenceLevel + && java.util.Objects.equals(mMediaSyncEvent, that.mMediaSyncEvent) && mByteOffset == that.mByteOffset && mScore == that.mScore && mPersonalizedScore == that.mPersonalizedScore @@ -288,6 +314,7 @@ public final class HotwordDetectedResult implements Parcelable { int _hash = 1; _hash = 31 * _hash + mConfidenceLevel; + _hash = 31 * _hash + java.util.Objects.hashCode(mMediaSyncEvent); _hash = 31 * _hash + mByteOffset; _hash = 31 * _hash + mScore; _hash = 31 * _hash + mPersonalizedScore; @@ -302,7 +329,11 @@ public final class HotwordDetectedResult implements Parcelable { // You can override field parcelling by defining methods like: // void parcelFieldName(Parcel dest, int flags) { ... } + byte flg = 0; + if (mMediaSyncEvent != null) flg |= 0x2; + dest.writeByte(flg); dest.writeInt(mConfidenceLevel); + if (mMediaSyncEvent != null) dest.writeTypedObject(mMediaSyncEvent, flags); dest.writeInt(mByteOffset); dest.writeInt(mScore); dest.writeInt(mPersonalizedScore); @@ -321,7 +352,9 @@ public final class HotwordDetectedResult implements Parcelable { // You can override field unparcelling by defining methods like: // static FieldType unparcelFieldName(Parcel in) { ... } + byte flg = in.readByte(); int confidenceLevel = in.readInt(); + MediaSyncEvent mediaSyncEvent = (flg & 0x2) == 0 ? null : (MediaSyncEvent) in.readTypedObject(MediaSyncEvent.CREATOR); int byteOffset = in.readInt(); int score = in.readInt(); int personalizedScore = in.readInt(); @@ -331,6 +364,7 @@ public final class HotwordDetectedResult implements Parcelable { this.mConfidenceLevel = confidenceLevel; com.android.internal.util.AnnotationValidations.validate( HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel); + this.mMediaSyncEvent = mediaSyncEvent; this.mByteOffset = byteOffset; this.mScore = score; this.mPersonalizedScore = personalizedScore; @@ -364,6 +398,7 @@ public final class HotwordDetectedResult implements Parcelable { public static final class Builder { private @HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel; + private @Nullable MediaSyncEvent mMediaSyncEvent; private int mByteOffset; private int mScore; private int mPersonalizedScore; @@ -387,14 +422,27 @@ public final class HotwordDetectedResult implements Parcelable { } /** + * A {@code MediaSyncEvent} that allows the {@link HotwordDetector} to recapture the audio + * that contains the hotword trigger. This must be obtained using + * {@link android.media.AudioRecord#shareAudioHistory(String, long)}. + * <p> + * This can be {@code null} if reprocessing the hotword trigger isn't required. + */ + @DataClass.Generated.Member + public @NonNull Builder setMediaSyncEvent(@NonNull MediaSyncEvent value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mMediaSyncEvent = value; + return this; + } + + /** * Byte offset in the audio stream when the trigger event happened. - * - * <p>If unset, the most recent bytes in the audio stream will be used. */ @DataClass.Generated.Member public @NonNull Builder setByteOffset(int value) { checkNotUsed(); - mBuilderFieldsSet |= 0x2; + mBuilderFieldsSet |= 0x4; mByteOffset = value; return this; } @@ -407,7 +455,7 @@ public final class HotwordDetectedResult implements Parcelable { @DataClass.Generated.Member public @NonNull Builder setScore(int value) { checkNotUsed(); - mBuilderFieldsSet |= 0x4; + mBuilderFieldsSet |= 0x8; mScore = value; return this; } @@ -420,7 +468,7 @@ public final class HotwordDetectedResult implements Parcelable { @DataClass.Generated.Member public @NonNull Builder setPersonalizedScore(int value) { checkNotUsed(); - mBuilderFieldsSet |= 0x8; + mBuilderFieldsSet |= 0x10; mPersonalizedScore = value; return this; } @@ -433,7 +481,7 @@ public final class HotwordDetectedResult implements Parcelable { @DataClass.Generated.Member public @NonNull Builder setHotwordPhraseId(int value) { checkNotUsed(); - mBuilderFieldsSet |= 0x10; + mBuilderFieldsSet |= 0x20; mHotwordPhraseId = value; return this; } @@ -449,11 +497,14 @@ public final class HotwordDetectedResult implements Parcelable { * * <p>The use of this method is discouraged, and support for it will be removed in future * versions of Android. + * + * <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents + * that can be used to communicate with other processes. */ @DataClass.Generated.Member public @NonNull Builder setExtras(@NonNull PersistableBundle value) { checkNotUsed(); - mBuilderFieldsSet |= 0x20; + mBuilderFieldsSet |= 0x40; mExtras = value; return this; } @@ -461,28 +512,32 @@ public final class HotwordDetectedResult implements Parcelable { /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull HotwordDetectedResult build() { checkNotUsed(); - mBuilderFieldsSet |= 0x40; // Mark builder used + mBuilderFieldsSet |= 0x80; // Mark builder used if ((mBuilderFieldsSet & 0x1) == 0) { mConfidenceLevel = defaultConfidenceLevel(); } if ((mBuilderFieldsSet & 0x2) == 0) { - mByteOffset = defaultByteOffset(); + mMediaSyncEvent = null; } if ((mBuilderFieldsSet & 0x4) == 0) { - mScore = defaultScore(); + mByteOffset = defaultByteOffset(); } if ((mBuilderFieldsSet & 0x8) == 0) { - mPersonalizedScore = defaultPersonalizedScore(); + mScore = defaultScore(); } if ((mBuilderFieldsSet & 0x10) == 0) { - mHotwordPhraseId = defaultHotwordPhraseId(); + mPersonalizedScore = defaultPersonalizedScore(); } if ((mBuilderFieldsSet & 0x20) == 0) { + mHotwordPhraseId = defaultHotwordPhraseId(); + } + if ((mBuilderFieldsSet & 0x40) == 0) { mExtras = defaultExtras(); } HotwordDetectedResult o = new HotwordDetectedResult( mConfidenceLevel, + mMediaSyncEvent, mByteOffset, mScore, mPersonalizedScore, @@ -492,7 +547,7 @@ public final class HotwordDetectedResult implements Parcelable { } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x40) != 0) { + if ((mBuilderFieldsSet & 0x80) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -500,10 +555,10 @@ public final class HotwordDetectedResult implements Parcelable { } @DataClass.Generated( - time = 1616965644404L, + time = 1619059352684L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java", - inputSignatures = "public static final int BYTE_OFFSET_UNSET\nprivate final @android.service.voice.HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate final int mByteOffset\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int defaultConfidenceLevel()\nprivate static int defaultByteOffset()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)") + inputSignatures = "public static final int BYTE_OFFSET_UNSET\nprivate final @android.service.voice.HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate final int mByteOffset\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int defaultConfidenceLevel()\nprivate static int defaultByteOffset()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java index ea854e8c9283..7e0117df288e 100644 --- a/core/java/android/service/voice/HotwordDetectionService.java +++ b/core/java/android/service/voice/HotwordDetectionService.java @@ -30,6 +30,7 @@ import android.app.Service; import android.content.ContentCaptureOptions; import android.content.Context; import android.content.Intent; +import android.hardware.soundtrigger.SoundTrigger; import android.media.AudioFormat; import android.os.Bundle; import android.os.Handler; @@ -133,7 +134,7 @@ public abstract class HotwordDetectionService extends Service { private final IHotwordDetectionService mInterface = new IHotwordDetectionService.Stub() { @Override public void detectFromDspSource( - ParcelFileDescriptor audioStream, + SoundTrigger.KeyphraseRecognitionEvent event, AudioFormat audioFormat, long timeoutMillis, IDspHotwordDetectionCallback callback) @@ -143,8 +144,9 @@ public abstract class HotwordDetectionService extends Service { } mHandler.sendMessage(obtainMessage(HotwordDetectionService::onDetect, HotwordDetectionService.this, - audioStream, - audioFormat, + new AlwaysOnHotwordDetector.EventPayload( + event.triggerInData, event.captureAvailable, + event.captureFormat, event.captureSession, event.data), timeoutMillis, new Callback(callback))); } @@ -178,8 +180,6 @@ public abstract class HotwordDetectionService extends Service { mHandler.sendMessage(obtainMessage( HotwordDetectionService::onDetect, HotwordDetectionService.this, - audioStream, - audioFormat, new Callback(callback))); break; case AUDIO_SOURCE_EXTERNAL: @@ -246,9 +246,12 @@ public abstract class HotwordDetectionService extends Service { * the application fails to abide by the timeout, system will close the * microphone and cancel the operation. * @param callback The callback to use for responding to the detection request. + * @deprecated Implement + * {@link #onDetect(AlwaysOnHotwordDetector.EventPayload, long, Callback)} instead. * * @hide */ + @Deprecated @SystemApi public void onDetect( @NonNull ParcelFileDescriptor audioStream, @@ -260,6 +263,32 @@ public abstract class HotwordDetectionService extends Service { } /** + * Called when the device hardware (such as a DSP) detected the hotword, to request second stage + * validation before handing over the audio to the {@link AlwaysOnHotwordDetector}. + * <p> + * After {@code callback} is invoked or {@code timeoutMillis} has passed, and invokes the + * appropriate {@link AlwaysOnHotwordDetector.Callback callback}. + * + * @param eventPayload Payload data for the hardware detection event. This may contain the + * trigger audio, if requested when calling + * {@link AlwaysOnHotwordDetector#startRecognition(int)}. + * @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 The callback to use for responding to the detection request. + * + * @hide + */ + @SystemApi + public void onDetect( + @NonNull AlwaysOnHotwordDetector.EventPayload eventPayload, + @DurationMillisLong long timeoutMillis, + @NonNull Callback callback) { + // TODO: Add a helpful error message. + throw new UnsupportedOperationException(); + } + + /** * Called when the {@link VoiceInteractionService#createAlwaysOnHotwordDetector(String, Locale, * PersistableBundle, SharedMemory, AlwaysOnHotwordDetector.Callback)} or * {@link AlwaysOnHotwordDetector#updateState(PersistableBundle, SharedMemory)} requests an @@ -305,7 +334,9 @@ public abstract class HotwordDetectionService extends Service { * @param audioFormat Format of the supplied audio * @param callback The callback to use for responding to the detection request. * {@link Callback#onRejected(HotwordRejectedResult) callback.onRejected} cannot be used here. + * @deprecated Implement {@link #onDetect(Callback)} instead. */ + @Deprecated public void onDetect( @NonNull ParcelFileDescriptor audioStream, @NonNull AudioFormat audioFormat, @@ -316,6 +347,22 @@ public abstract class HotwordDetectionService extends Service { /** * Called when the {@link VoiceInteractionService} requests that this service + * {@link HotwordDetector#startRecognition() start} hotword recognition on audio coming directly + * from the device microphone. + * <p> + * On successful detection of a hotword, call + * {@link Callback#onDetected(HotwordDetectedResult)}. + * + * @param callback The callback to use for responding to the detection request. + * {@link Callback#onRejected(HotwordRejectedResult) callback.onRejected} cannot be used here. + */ + public void onDetect(@NonNull Callback callback) { + // TODO: Add a helpful error message. + throw new UnsupportedOperationException(); + } + + /** + * Called when the {@link VoiceInteractionService} requests that this service * {@link HotwordDetector#startRecognition(ParcelFileDescriptor, AudioFormat, * PersistableBundle)} run} hotword recognition on audio coming from an external connected * microphone. diff --git a/core/java/android/service/voice/IHotwordDetectionService.aidl b/core/java/android/service/voice/IHotwordDetectionService.aidl index 2ffe787e895a..7ba00982e6a2 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.content.ContentCaptureOptions; +import android.hardware.soundtrigger.SoundTrigger; import android.media.AudioFormat; import android.os.IRemoteCallback; import android.os.ParcelFileDescriptor; @@ -23,7 +25,6 @@ import android.os.PersistableBundle; import android.os.SharedMemory; import android.service.voice.IDspHotwordDetectionCallback; import android.view.contentcapture.IContentCaptureManager; -import android.content.ContentCaptureOptions; /** * Provide the interface to communicate with hotword detection service. @@ -32,7 +33,7 @@ import android.content.ContentCaptureOptions; */ oneway interface IHotwordDetectionService { void detectFromDspSource( - in ParcelFileDescriptor audioStream, + in SoundTrigger.KeyphraseRecognitionEvent event, in AudioFormat audioFormat, long timeoutMillis, in IDspHotwordDetectionCallback callback); diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 2a2522741955..b5c838b1871b 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -420,9 +420,13 @@ public class VoiceInteractionService extends Service { * * @see #createAlwaysOnHotwordDetector(String, Locale, PersistableBundle, SharedMemory, * AlwaysOnHotwordDetector.Callback) + * @deprecated Use + * {@link #createHotwordDetector(PersistableBundle, SharedMemory, HotwordDetector.Callback)} + * instead. * * @hide */ + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION) @NonNull @@ -445,6 +449,58 @@ public class VoiceInteractionService extends Service { } /** + * Creates a {@link HotwordDetector} and initializes the application's + * {@link HotwordDetectionService} using {@code options} and {code sharedMemory}. + * + * <p>To be able to call this, you need to set android:hotwordDetectionService in the + * android.voice_interaction metadata file to a valid hotword detection service, and set + * android:isolatedProcess="true" in the hotword detection service's declaration. Otherwise, + * this throws an {@link IllegalStateException}. + * + * <p>This instance must be retained and used by the client. + * Calling this a second time invalidates the previously created hotword detector + * which can no longer be used to manage recognition. + * + * <p>Using this has a noticeable impact on battery, since the microphone is kept open + * for the lifetime of the recognition {@link HotwordDetector#startRecognition() session}. On + * devices where hardware filtering is available (such as through a DSP), it's highly + * recommended to use {@link #createAlwaysOnHotwordDetector} instead. + * + * @param options Application configuration data to be provided to the + * {@link HotwordDetectionService}. PersistableBundle does not allow any remotable objects or + * other contents that can be used to communicate with other processes. + * @param sharedMemory The unrestricted data blob to be provided to the + * {@link HotwordDetectionService}. Use this to provide hotword models or other such data to the + * sandboxed process. + * @param callback The callback to notify of detection events. + * @return A hotword detector for the given audio format. + * + * @see #createAlwaysOnHotwordDetector(String, Locale, PersistableBundle, SharedMemory, + * AlwaysOnHotwordDetector.Callback) + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION) + @NonNull + public final HotwordDetector createHotwordDetector( + @Nullable PersistableBundle options, + @Nullable SharedMemory sharedMemory, + @NonNull HotwordDetector.Callback callback) { + if (mSystemService == null) { + throw new IllegalStateException("Not available until onReady() is called"); + } + synchronized (mLock) { + // Allow only one concurrent recognition via the APIs. + safelyShutdownHotwordDetector(); + mSoftwareHotwordDetector = + new SoftwareHotwordDetector( + mSystemService, null, options, sharedMemory, callback); + } + return mSoftwareHotwordDetector; + } + + /** * Creates an {@link KeyphraseModelManager} to use for enrolling voice models outside of the * pre-bundled system voice models. * @hide diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 87fb611d2a0b..53bde36a8a64 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -254,6 +254,7 @@ public abstract class WallpaperService extends Service { private int mDisplayState; SurfaceControl mSurfaceControl = new SurfaceControl(); + SurfaceControl mBbqSurfaceControl; BLASTBufferQueue mBlastBufferQueue; final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() { @@ -976,6 +977,15 @@ public abstract class WallpaperService extends Service { View.VISIBLE, 0, -1, mWinFrames, mMergedConfiguration, mSurfaceControl, mInsetsState, mTempControls, mSurfaceSize); if (mSurfaceControl.isValid()) { + if (mBbqSurfaceControl == null) { + mBbqSurfaceControl = new SurfaceControl.Builder() + .setName("Wallpaper BBQ wrapper") + .setHidden(false) + .setBLASTLayer() + .setParent(mSurfaceControl) + .setCallsite("Wallpaper#relayout") + .build(); + } Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x, mSurfaceSize.y, mFormat); // If blastSurface == null that means it hasn't changed since the last @@ -987,11 +997,6 @@ public abstract class WallpaperService extends Service { } if (!mLastSurfaceSize.equals(mSurfaceSize)) { mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y); - if (mSurfaceControl != null && mSurfaceControl.isValid()) { - SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - t.setBufferSize(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y); - t.apply(); - } } if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface @@ -1830,6 +1835,14 @@ public abstract class WallpaperService extends Service { } catch (RemoteException e) { } mSurfaceHolder.mSurface.release(); + if (mBlastBufferQueue != null) { + mBlastBufferQueue.destroy(); + mBlastBufferQueue = null; + } + if (mBbqSurfaceControl != null) { + new SurfaceControl.Transaction().remove(mBbqSurfaceControl).apply(); + mBbqSurfaceControl = null; + } mCreated = false; } } @@ -1854,13 +1867,13 @@ public abstract class WallpaperService extends Service { private Surface getOrCreateBLASTSurface(int width, int height, int format) { Surface ret = null; if (mBlastBufferQueue == null) { - mBlastBufferQueue = new BLASTBufferQueue("Wallpaper", mSurfaceControl, width, - height, format); + mBlastBufferQueue = new BLASTBufferQueue("Wallpaper", mBbqSurfaceControl, + width, height, format); // We only return the Surface the first time, as otherwise // it hasn't changed and there is no need to update. ret = mBlastBufferQueue.createSurface(); } else { - mBlastBufferQueue.update(mSurfaceControl, width, height, format); + mBlastBufferQueue.update(mBbqSurfaceControl, width, height, format); } return ret; diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java index 22ccd23a22bc..3183f15fe16c 100644 --- a/core/java/android/speech/RecognizerIntent.java +++ b/core/java/android/speech/RecognizerIntent.java @@ -43,7 +43,7 @@ public class RecognizerIntent { /** * The extra key used in an intent which is providing an already opened audio source for the - * RecognitionService to use. + * RecognitionService to use. Data should be a URI to an audio resource. */ public static final String EXTRA_AUDIO_INJECT_SOURCE = "android.speech.extra.AUDIO_INJECT_SOURCE"; diff --git a/core/java/android/view/ContentInfo.java b/core/java/android/view/ContentInfo.java index b55d9b3a1913..7966712dc119 100644 --- a/core/java/android/view/ContentInfo.java +++ b/core/java/android/view/ContentInfo.java @@ -164,6 +164,7 @@ public final class ContentInfo { * * @hide */ + @TestApi public void releasePermissions() { if (mInputContentInfo != null) { mInputContentInfo.releasePermission(); @@ -388,6 +389,8 @@ public final class ContentInfo { * * @hide */ + @TestApi + @SuppressLint("MissingGetterMatchingBuilder") @NonNull public Builder setInputContentInfo(@Nullable InputContentInfo inputContentInfo) { mInputContentInfo = inputContentInfo; @@ -400,6 +403,8 @@ public final class ContentInfo { * * @hide */ + @TestApi + @SuppressLint("MissingGetterMatchingBuilder") @NonNull public Builder setDragAndDropPermissions(@Nullable DragAndDropPermissions permissions) { mDragAndDropPermissions = permissions; diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 88406ffcdf14..cd8248934be7 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -857,7 +857,5 @@ interface IWindowManager */ void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener); - void setForceCrossWindowBlurDisabled(boolean disable); - boolean isTaskSnapshotSupported(); } diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index 3b1c8ec23016..4f1354d7eee6 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -22,7 +22,7 @@ import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; -import android.hardware.Battery; +import android.hardware.BatteryState; import android.hardware.SensorManager; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; @@ -88,7 +88,7 @@ public final class InputDevice implements Parcelable { private SensorManager mSensorManager; @GuardedBy("mMotionRanges") - private Battery mBattery; + private BatteryState mBatteryState; @GuardedBy("mMotionRanges") private LightsManager mLightsManager; @@ -848,19 +848,19 @@ public final class InputDevice implements Parcelable { } /** - * Gets the battery object associated with the device, if there is one. + * Gets the battery state object associated with the device, if there is one. * Even if the device does not have a battery, the result is never null. - * Use {@link Battery#hasBattery} to determine whether a battery is + * Use {@link BatteryState#isPresent} to determine whether a battery is * present. * * @return The battery object associated with the device, never null. */ @NonNull - public Battery getBattery() { - if (mBattery == null) { - mBattery = InputManager.getInstance().getInputDeviceBattery(mId, mHasBattery); + public BatteryState getBatteryState() { + if (mBatteryState == null) { + mBatteryState = InputManager.getInstance().getInputDeviceBatteryState(mId, mHasBattery); } - return mBattery; + return mBatteryState; } /** diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index aa3c9d6e14f9..ff2d2eb3d334 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -936,18 +936,21 @@ public class Surface implements Parcelable { * @param frameRate The intended frame rate of this surface, in frames per second. 0 * is a special value that indicates the app will accept the system's choice for the * display frame rate, which is the default behavior if this function isn't - * called. The frameRate param does <em>not</em> need to be a valid refresh rate for - * this device's display - e.g., it's fine to pass 30fps to a device that can only run + * called. The <code>frameRate</code> parameter does <em>not</em> need to be a valid refresh + * rate for this device's display - e.g., it's fine to pass 30fps to a device that can only run * the display at 60fps. * * @param compatibility The frame rate compatibility of this surface. The * compatibility value may influence the system's choice of display frame rate. + * This parameter is ignored when <code>frameRate</code> is 0. * - * @param changeFrameRateStrategy Whether display refresh rate transitions should be seamless. A - * seamless transition is one that doesn't have any visual interruptions, such as a black - * screen for a second or two. + * @param changeFrameRateStrategy Whether display refresh rate transitions caused by this + * surface should be seamless. A seamless transition is one that doesn't have any visual + * interruptions, such as a black screen for a second or two. This parameter is ignored when + * <code>frameRate</code> is 0. * - * @throws IllegalArgumentException If frameRate or compatibility are invalid. + * @throws IllegalArgumentException If <code>frameRate</code>, <code>compatibility</code> or + * <code>changeFrameRateStrategy</code> are invalid. */ public void setFrameRate(@FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility, diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 3ff7a65b6c6a..ac70dff4f03e 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -3298,20 +3298,26 @@ public final class SurfaceControl implements Parcelable { * because the system may change the display refresh rate, calls to this function may result * in changes to Choreographer callback timings, and changes to the time interval at which * the system releases buffers back to the application. + * <p> + * Note that this only has an effect for surfaces presented on the display. If this + * surface is consumed by something other than the system compositor, e.g. a media + * codec, this call has no effect. * * @param sc The SurfaceControl to specify the frame rate of. * @param frameRate The intended frame rate for this surface, in frames per second. 0 is a * special value that indicates the app will accept the system's choice for * the display frame rate, which is the default behavior if this function - * isn't called. The frameRate param does <em>not</em> need to be a valid - * refresh rate for this device's display - e.g., it's fine to pass 30fps - * to a device that can only run the display at 60fps. + * isn't called. The <code>frameRate</code> param does <em>not</em> need + * to be a valid refresh rate for this device's display - e.g., it's fine + * to pass 30fps to a device that can only run the display at 60fps. * @param compatibility The frame rate compatibility of this surface. The compatibility * value may influence the system's choice of display frame rate. - * @param changeFrameRateStrategy Whether display refresh rate transitions should be - * seamless. A seamless transition is one that doesn't have - * any visual interruptions, such as a black screen for a - * second or two. + * This parameter is ignored when <code>frameRate</code> is 0. + * @param changeFrameRateStrategy Whether display refresh rate transitions caused by this + * surface should be seamless. A seamless transition is one + * that doesn't have any visual interruptions, such as a + * black screen for a second or two. This parameter is + * ignored when <code>frameRate</code> is 0. * @return This transaction object. */ @NonNull diff --git a/core/java/android/view/TEST_MAPPING b/core/java/android/view/TEST_MAPPING index c8b746f2248f..50d69f78688a 100644 --- a/core/java/android/view/TEST_MAPPING +++ b/core/java/android/view/TEST_MAPPING @@ -20,6 +20,21 @@ } ], "file_patterns": ["(/|^)ViewConfiguration.java", "(/|^)GestureDetector.java"] + }, + { + "name": "CtsViewReceiveContentTestCases", + "options": [ + { + "include-annotation": "android.platform.test.annotations.Presubmit" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ], + "file_patterns": ["ContentInfo\\.java", "OnReceiveContentListener\\.java", "View\\.java"] } ], "imports": [ diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 5a738eb2878a..0958f3fbd771 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -5191,6 +5191,17 @@ public final class ViewRootImpl implements ViewParent, @Override public void handleMessage(Message msg) { + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, getMessageName(msg)); + } + try { + handleMessageImpl(msg); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } + } + + private void handleMessageImpl(Message msg) { switch (msg.what) { case MSG_INVALIDATE: ((View) msg.obj).invalidate(); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 60516eb9efd4..c32ab3a2d717 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -908,20 +908,6 @@ public interface WindowManager extends ViewManager { } /** - * Disables cross-window blurs device-wide. This includes window blur behind - * (see {@link LayoutParams#setBlurBehindRadius}) and window background blur - * (see {@link Window#setBackgroundBlurRadius}). - * - * @param disable specifies whether to disable the blur. Note that calling this - * with 'disable=false' will not enable blurs if there is something - * else disabling blurs. - * @hide - */ - @TestApi - default void setForceCrossWindowBlurDisabled(boolean disable) { - } - - /** * @hide */ static String transitTypeToString(@TransitionType int type) { diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 07eeb034b663..f800991944ac 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -328,15 +328,6 @@ public final class WindowManagerImpl implements WindowManager { } @Override - public void setForceCrossWindowBlurDisabled(boolean disable) { - try { - WindowManagerGlobal.getWindowManagerService() - .setForceCrossWindowBlurDisabled(disable); - } catch (RemoteException e) { - } - } - - @Override public boolean isTaskSnapshotSupported() { try { return WindowManagerGlobal.getWindowManagerService().isTaskSnapshotSupported(); diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index d6292caba344..6694b7eb9ac2 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -93,6 +93,7 @@ import com.android.internal.inputmethod.Completable; import com.android.internal.inputmethod.InputMethodDebug; import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry; import com.android.internal.inputmethod.ResultCallbacks; +import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.inputmethod.StartInputFlags; import com.android.internal.inputmethod.StartInputReason; import com.android.internal.inputmethod.UnbindReason; @@ -266,6 +267,14 @@ public final class InputMethodManager { private static final int NOT_A_SUBTYPE_ID = -1; /** + * {@code true} to try to avoid blocking apps' UI thread by sending + * {@link StartInputReason#WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION} and + * {@link StartInputReason#WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION} in a truly asynchronous + * way. {@code false} to go back to the previous synchronous semantics. + */ + private static final boolean USE_REPORT_WINDOW_GAINED_FOCUS_ASYNC = true; + + /** * A constant that represents Voice IME. * * @see InputMethodSubtype#getMode() @@ -689,20 +698,29 @@ public final class InputMethodManager { Log.v(TAG, "Reporting focus gain, without startInput" + ", nextFocusIsServedView=" + nextFocusHasConnection); } - final int startInputReason = - nextFocusHasConnection ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION - : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION; - final Completable.InputBindResult value = Completable.createInputBindResult(); - mService.startInputOrWindowGainedFocus( - startInputReason, mClient, - focusedView.getWindowToken(), startInputFlags, softInputMode, - windowFlags, - null, - null, - 0 /* missingMethodFlags */, - mCurRootView.mContext.getApplicationInfo().targetSdkVersion, - ResultCallbacks.of(value)); - Completable.getResult(value); // ignore the result + + if (USE_REPORT_WINDOW_GAINED_FOCUS_ASYNC) { + mService.reportWindowGainedFocusAsync( + nextFocusHasConnection, mClient, focusedView.getWindowToken(), + startInputFlags, softInputMode, windowFlags, + mCurRootView.mContext.getApplicationInfo().targetSdkVersion); + } else { + final int startInputReason = nextFocusHasConnection + ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION + : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION; + final Completable.InputBindResult value = + Completable.createInputBindResult(); + mService.startInputOrWindowGainedFocus( + startInputReason, mClient, + focusedView.getWindowToken(), startInputFlags, softInputMode, + windowFlags, + null, + null, + 0 /* missingMethodFlags */, + mCurRootView.mContext.getApplicationInfo().targetSdkVersion, + ResultCallbacks.of(value)); + Completable.getResult(value); // ignore the result + } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1087,6 +1105,11 @@ public final class InputMethodManager { public void setImeTraceEnabled(boolean enabled) { ImeTracing.getInstance().setEnabled(enabled); } + + @Override + public void throwExceptionFromSystem(String message) { + throw new RuntimeException(message); + } }; final InputConnection mDummyInputConnection = new BaseInputConnection(this, false); @@ -1383,7 +1406,8 @@ public final class InputMethodManager { */ @Deprecated public void showStatusIcon(IBinder imeToken, String packageName, @DrawableRes int iconId) { - InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIcon(packageName, iconId); + InputMethodPrivilegedOperationsRegistry.get( + imeToken).updateStatusIconAsync(packageName, iconId); } /** @@ -1393,7 +1417,7 @@ public final class InputMethodManager { */ @Deprecated public void hideStatusIcon(IBinder imeToken) { - InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIcon(null, 0); + InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIconAsync(null, 0); } /** @@ -1674,6 +1698,11 @@ public final class InputMethodManager { * {@link #RESULT_HIDDEN}. */ public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) { + return showSoftInput(view, flags, resultReceiver, SoftInputShowHideReason.SHOW_SOFT_INPUT); + } + + private boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver, + @SoftInputShowHideReason int reason) { ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this, null /* icProto */); // Re-dispatch if there is a context mismatch. @@ -1690,13 +1719,15 @@ public final class InputMethodManager { } try { - Log.d(TAG, "showSoftInput() view=" + view + " flags=" + flags); + Log.d(TAG, "showSoftInput() view=" + view + " flags=" + flags + " reason=" + + InputMethodDebug.softInputDisplayReasonToString(reason)); final Completable.Boolean value = Completable.createBoolean(); mService.showSoftInput( mClient, view.getWindowToken(), flags, resultReceiver, + reason, ResultCallbacks.of(value)); return Completable.getResult(value); } catch (RemoteException e) { @@ -1731,6 +1762,7 @@ public final class InputMethodManager { mCurRootView.getView().getWindowToken(), flags, resultReceiver, + SoftInputShowHideReason.SHOW_SOFT_INPUT, ResultCallbacks.of(value)); Completable.getResult(value); // ignore the result } catch (RemoteException e) { @@ -1795,6 +1827,12 @@ public final class InputMethodManager { */ public boolean hideSoftInputFromWindow(IBinder windowToken, int flags, ResultReceiver resultReceiver) { + return hideSoftInputFromWindow(windowToken, flags, resultReceiver, + SoftInputShowHideReason.HIDE_SOFT_INPUT); + } + + private boolean hideSoftInputFromWindow(IBinder windowToken, int flags, + ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) { ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow", this, null /* icProto */); checkFocus(); @@ -1806,8 +1844,8 @@ public final class InputMethodManager { try { final Completable.Boolean value = Completable.createBoolean(); - mService.hideSoftInput( - mClient, windowToken, flags, resultReceiver, ResultCallbacks.of(value)); + mService.hideSoftInput(mClient, windowToken, flags, resultReceiver, reason, + ResultCallbacks.of(value)); return Completable.getResult(value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1827,7 +1865,14 @@ public final class InputMethodManager { * @param hideFlags Provides additional operating flags. May be * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, * {@link #HIDE_NOT_ALWAYS} bit set. - **/ + * + * @deprecated Use {@link #showSoftInput(View, int)} or + * {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead. + * In particular during focus changes, the current visibility of the IME is not + * well defined. Starting in {@link Build.VERSION_CODES#S Android S}, this only + * has an effect if the calling app is the current IME focus. + */ + @Deprecated public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) { ImeTracing.getInstance().triggerClientDump( "InputMethodManager#toggleSoftInputFromWindow", InputMethodManager.this, @@ -1837,9 +1882,7 @@ public final class InputMethodManager { if (servedView == null || servedView.getWindowToken() != windowToken) { return; } - if (mCurrentInputMethodSession != null) { - mCurrentInputMethodSession.toggleSoftInput(showFlags, hideFlags); - } + toggleSoftInput(showFlags, hideFlags); } } @@ -1854,13 +1897,29 @@ public final class InputMethodManager { * @param hideFlags Provides additional operating flags. May be * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, * {@link #HIDE_NOT_ALWAYS} bit set. + * + * @deprecated Use {@link #showSoftInput(View, int)} or + * {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead. + * In particular during focus changes, the current visibility of the IME is not + * well defined. Starting in {@link Build.VERSION_CODES#S Android S}, this only + * has an effect if the calling app is the current IME focus. */ + @Deprecated public void toggleSoftInput(int showFlags, int hideFlags) { ImeTracing.getInstance().triggerClientDump( "InputMethodManager#toggleSoftInput", InputMethodManager.this, null /* icProto */); - if (mCurrentInputMethodSession != null) { - mCurrentInputMethodSession.toggleSoftInput(showFlags, hideFlags); + synchronized (mH) { + final View view = getServedViewLocked(); + if (mImeInsetsConsumer != null && view != null) { + if (mImeInsetsConsumer.isRequestedVisible()) { + hideSoftInputFromWindow(view.getWindowToken(), hideFlags, null, + SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT); + } else { + showSoftInput(view, showFlags, null, + SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT); + } + } } } @@ -2144,6 +2203,7 @@ public final class InputMethodManager { mCurRootView.getView().getWindowToken(), HIDE_NOT_ALWAYS, null, + SoftInputShowHideReason.HIDE_SOFT_INPUT, ResultCallbacks.of(value)); Completable.getResult(value); // ignore the result } catch (RemoteException e) { @@ -2199,7 +2259,8 @@ public final class InputMethodManager { if (servedView == null || servedView.getWindowToken() != windowToken) { return false; } - showSoftInput(servedView, 0 /* flags */, null /* resultReceiver */); + showSoftInput(servedView, 0 /* flags */, null /* resultReceiver */, + SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API); return true; } } diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java index 0d688ffa44c8..52c1cd4f628a 100644 --- a/core/java/android/view/inputmethod/InputMethodSession.java +++ b/core/java/android/view/inputmethod/InputMethodSession.java @@ -17,6 +17,8 @@ package android.view.inputmethod; import android.graphics.Rect; +import android.inputmethodservice.InputMethodService; +import android.os.Build; import android.os.Bundle; import android.view.KeyEvent; import android.view.MotionEvent; @@ -172,7 +174,13 @@ public interface InputMethodSession { * @param hideFlags Provides additional operating flags. May be * 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY}, * {@link InputMethodManager#HIDE_NOT_ALWAYS} bit set. + * + * @deprecated Starting in {@link Build.VERSION_CODES#S} the system no longer invokes this + * method, instead it explicitly shows or hides the IME. An {@code InputMethodService} + * wishing to toggle its own visibility should instead invoke {@link + * InputMethodService#requestShowSelf} or {@link InputMethodService#requestHideSelf} */ + @Deprecated public void toggleSoftInput(int showFlags, int hideFlags); /** diff --git a/core/java/android/view/inputmethod/InputMethodSessionWrapper.java b/core/java/android/view/inputmethod/InputMethodSessionWrapper.java index c4a3773f87e3..ef1814b7bdf2 100644 --- a/core/java/android/view/inputmethod/InputMethodSessionWrapper.java +++ b/core/java/android/view/inputmethod/InputMethodSessionWrapper.java @@ -96,15 +96,6 @@ final class InputMethodSessionWrapper { } @AnyThread - void toggleSoftInput(int showFlags, int hideFlags) { - try { - mSession.toggleSoftInput(showFlags, hideFlags); - } catch (RemoteException e) { - Log.w(TAG, "IME died", e); - } - } - - @AnyThread void appPrivateCommand(String action, Bundle data) { try { mSession.appPrivateCommand(action, data); diff --git a/core/java/android/view/translation/ITranslationManager.aidl b/core/java/android/view/translation/ITranslationManager.aidl index 560edecc9da6..5fbf228ec72f 100644 --- a/core/java/android/view/translation/ITranslationManager.aidl +++ b/core/java/android/view/translation/ITranslationManager.aidl @@ -22,6 +22,7 @@ import android.os.ResultReceiver; import android.view.autofill.AutofillId; import android.view.translation.TranslationContext; import android.view.translation.TranslationSpec; +import android.view.translation.UiTranslationSpec; import com.android.internal.os.IResultReceiver; import java.util.List; @@ -34,12 +35,14 @@ import java.util.List; oneway interface ITranslationManager { void onTranslationCapabilitiesRequest(int sourceFormat, int destFormat, in ResultReceiver receiver, int userId); + void registerTranslationCapabilityCallback(in IRemoteCallback callback, int userId); + void unregisterTranslationCapabilityCallback(in IRemoteCallback callback, int userId); void onSessionCreated(in TranslationContext translationContext, int sessionId, in IResultReceiver receiver, int userId); void updateUiTranslationState(int state, in TranslationSpec sourceSpec, in TranslationSpec targetSpec, in List<AutofillId> viewIds, IBinder token, int taskId, - int userId); + in UiTranslationSpec uiTranslationSpec, int userId); void registerUiTranslationStateCallback(in IRemoteCallback callback, int userId); void unregisterUiTranslationStateCallback(in IRemoteCallback callback, int userId); diff --git a/core/java/android/view/translation/TranslationManager.java b/core/java/android/view/translation/TranslationManager.java index 52790f6822ff..20d817db02b3 100644 --- a/core/java/android/view/translation/TranslationManager.java +++ b/core/java/android/view/translation/TranslationManager.java @@ -16,6 +16,7 @@ package android.view.translation; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; @@ -41,12 +42,14 @@ import com.android.internal.util.SyncResultReceiver; import java.util.ArrayList; import java.util.Collections; +import java.util.Map; import java.util.Objects; import java.util.Random; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; /** * The {@link TranslationManager} class provides ways for apps to integrate and use the @@ -81,11 +84,14 @@ public final class TranslationManager { */ public static final String EXTRA_CAPABILITIES = "translation_capabilities"; - // TODO: implement update listeners and propagate updates. @GuardedBy("mLock") private final ArrayMap<Pair<Integer, Integer>, ArrayList<PendingIntent>> mTranslationCapabilityUpdateListeners = new ArrayMap<>(); + @GuardedBy("mLock") + private final Map<Consumer<TranslationCapability>, IRemoteCallback> mCapabilityCallbacks = + new ArrayMap<>(); + private static final Random ID_GENERATOR = new Random(); private final Object mLock = new Object(); @@ -94,10 +100,6 @@ public final class TranslationManager { private final ITranslationManager mService; - @Nullable - @GuardedBy("mLock") - private ITranslationDirectManager mDirectServiceBinder; - @NonNull @GuardedBy("mLock") private final SparseArray<Translator> mTranslators = new SparseArray<>(); @@ -125,11 +127,72 @@ public final class TranslationManager { /** * Creates an on-device Translator for natural language translation. * + * @param translationContext {@link TranslationContext} containing the specs for creating the + * Translator. + * @param executor Executor to run callback operations + * @param callback {@link Consumer} to receive the translator. A {@code null} value is returned + * if the service could not create the translator. + */ + public void createOnDeviceTranslator(@NonNull TranslationContext translationContext, + @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Translator> callback) { + Objects.requireNonNull(translationContext, "translationContext cannot be null"); + Objects.requireNonNull(executor, "executor cannot be null"); + Objects.requireNonNull(callback, "callback cannot be null"); + + synchronized (mLock) { + // TODO(b/176464808): Disallow multiple Translator now, it will throw + // IllegalStateException. Need to discuss if we can allow multiple Translators. + if (mTranslatorIds.containsKey(translationContext)) { + executor.execute(() -> callback.accept( + mTranslators.get(mTranslatorIds.get(translationContext)))); + return; + } + + int translatorId; + do { + translatorId = Math.abs(ID_GENERATOR.nextInt()); + } while (translatorId == 0 || mTranslators.indexOfKey(translatorId) >= 0); + final int tId = translatorId; + + new Translator(mContext, translationContext, translatorId, this, mHandler, mService, + new Consumer<Translator>() { + @Override + public void accept(Translator translator) { + if (translator == null) { + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.accept(null)); + } finally { + Binder.restoreCallingIdentity(token); + } + return; + } + + mTranslators.put(tId, translator); + mTranslatorIds.put(translationContext, tId); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.accept(translator)); + } finally { + Binder.restoreCallingIdentity(token); + } + } + }); + } + } + + /** + * Creates an on-device Translator for natural language translation. + * * <p><strong>NOTE: </strong>Call on a worker thread. * + * @deprecated use {@link #createOnDeviceTranslator(TranslationContext, Executor, Consumer)} + * instead. + * * @param translationContext {@link TranslationContext} containing the specs for creating the * Translator. */ + @Deprecated @Nullable @WorkerThread public Translator createOnDeviceTranslator(@NonNull TranslationContext translationContext) { @@ -232,17 +295,43 @@ public final class TranslationManager { } /** - * Registers a {@link PendingIntent} to listen for updates on states of on-device + * Adds a {@link TranslationCapability} Consumer to listen for updates on states of on-device * {@link TranslationCapability}s. * - * <p>IMPORTANT: the pending intent must be called to start a service, or a broadcast if it is - * an explicit intent.</p> - * - * @param sourceFormat data format for the input data to be translated. - * @param targetFormat data format for the expected translated output data. - * @param pendingIntent the pending intent to invoke when updates are received. + * @param capabilityListener a {@link TranslationCapability} Consumer to receive the updated + * {@link TranslationCapability} from the on-device translation service. */ public void addOnDeviceTranslationCapabilityUpdateListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<TranslationCapability> capabilityListener) { + Objects.requireNonNull(executor, "executor should not be null"); + Objects.requireNonNull(capabilityListener, "capability listener should not be null"); + + synchronized (mLock) { + if (mCapabilityCallbacks.containsKey(capabilityListener)) { + Log.w(TAG, "addOnDeviceTranslationCapabilityUpdateListener: the listener for " + + capabilityListener + " already registered; ignoring."); + return; + } + final IRemoteCallback remoteCallback = new TranslationCapabilityRemoteCallback(executor, + capabilityListener); + try { + mService.registerTranslationCapabilityCallback(remoteCallback, + mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mCapabilityCallbacks.put(capabilityListener, remoteCallback); + } + } + + + /** + * @deprecated Use {@link TranslationManager#addOnDeviceTranslationCapabilityUpdateListener( + * java.util.concurrent.Executor, java.util.function.Consumer)} + */ + @Deprecated + public void addOnDeviceTranslationCapabilityUpdateListener( @TranslationSpec.DataFormat int sourceFormat, @TranslationSpec.DataFormat int targetFormat, @NonNull PendingIntent pendingIntent) { @@ -256,8 +345,8 @@ public final class TranslationManager { } /** - * @deprecated Use {@link #addOnDeviceTranslationCapabilityUpdateListener(int, int, - * PendingIntent)} + * @deprecated Use {@link TranslationManager#addOnDeviceTranslationCapabilityUpdateListener( + * java.util.concurrent.Executor, java.util.function.Consumer)} */ @Deprecated public void addTranslationCapabilityUpdateListener( @@ -268,14 +357,38 @@ public final class TranslationManager { } /** - * Unregisters a {@link PendingIntent} to listen for updates on states of on-device - * {@link TranslationCapability}s. + * Removes a {@link TranslationCapability} Consumer to listen for updates on states of + * on-device {@link TranslationCapability}s. * - * @param sourceFormat data format for the input data to be translated. - * @param targetFormat data format for the expected translated output data. - * @param pendingIntent the pending intent to unregister + * @param capabilityListener the {@link TranslationCapability} Consumer to unregister */ public void removeOnDeviceTranslationCapabilityUpdateListener( + @NonNull Consumer<TranslationCapability> capabilityListener) { + Objects.requireNonNull(capabilityListener, "capability callback should not be null"); + + synchronized (mLock) { + final IRemoteCallback remoteCallback = mCapabilityCallbacks.get(capabilityListener); + if (remoteCallback == null) { + Log.w(TAG, "removeOnDeviceTranslationCapabilityUpdateListener: the capability " + + "listener not found; ignoring."); + return; + } + try { + mService.unregisterTranslationCapabilityCallback(remoteCallback, + mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mCapabilityCallbacks.remove(capabilityListener); + } + } + + /** + * @deprecated Use {@link #removeOnDeviceTranslationCapabilityUpdateListener( + * java.util.function.Consumer)}. + */ + @Deprecated + public void removeOnDeviceTranslationCapabilityUpdateListener( @TranslationSpec.DataFormat int sourceFormat, @TranslationSpec.DataFormat int targetFormat, @NonNull PendingIntent pendingIntent) { @@ -300,8 +413,8 @@ public final class TranslationManager { } /** - * @deprecated Use {@link #removeOnDeviceTranslationCapabilityUpdateListener(int, int, - * PendingIntent)} + * @deprecated Use {@link #removeOnDeviceTranslationCapabilityUpdateListener( + * java.util.function.Consumer)}. */ @Deprecated public void removeTranslationCapabilityUpdateListener( @@ -366,9 +479,12 @@ public final class TranslationManager { private static class TranslationCapabilityRemoteCallback extends IRemoteCallback.Stub { private final Executor mExecutor; + private final Consumer<TranslationCapability> mListener; - TranslationCapabilityRemoteCallback(Executor executor) { + TranslationCapabilityRemoteCallback(Executor executor, + Consumer<TranslationCapability> listener) { mExecutor = executor; + mListener = listener; } @Override @@ -378,9 +494,9 @@ public final class TranslationManager { } private void onTranslationCapabilityUpdate(Bundle bundle) { - TranslationCapability capability = (TranslationCapability) bundle.getParcelable( - EXTRA_CAPABILITIES); - //TODO: Implement after deciding how capability listeners are implemented. + TranslationCapability capability = + (TranslationCapability) bundle.getParcelable(EXTRA_CAPABILITIES); + mListener.accept(capability); } } } diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java index 6037302a9445..8dbce1b4f53e 100644 --- a/core/java/android/view/translation/Translator.java +++ b/core/java/android/view/translation/Translator.java @@ -101,10 +101,18 @@ public class Translator { public static final String EXTRA_SESSION_ID = "sessionId"; static class ServiceBinderReceiver extends IResultReceiver.Stub { + // TODO: refactor how translator is instantiated after removing deprecated createTranslator. private final WeakReference<Translator> mTranslator; private final CountDownLatch mLatch = new CountDownLatch(1); private int mSessionId; + private Consumer<Translator> mCallback; + + ServiceBinderReceiver(Translator translator, Consumer<Translator> callback) { + mTranslator = new WeakReference<>(translator); + mCallback = callback; + } + ServiceBinderReceiver(Translator translator) { mTranslator = new WeakReference<>(translator); } @@ -126,6 +134,9 @@ public class Translator { public void send(int resultCode, Bundle resultData) { if (resultCode == STATUS_SYNC_CALL_FAIL) { mLatch.countDown(); + if (mCallback != null) { + mCallback.accept(null); + } return; } mSessionId = resultData.getInt(EXTRA_SESSION_ID); @@ -146,6 +157,9 @@ public class Translator { } translator.setServiceBinder(binder); mLatch.countDown(); + if (mCallback != null) { + mCallback.accept(translator); + } } // TODO(b/176464808): maybe make SyncResultReceiver.TimeoutException constructor public @@ -165,6 +179,32 @@ public class Translator { public Translator(@NonNull Context context, @NonNull TranslationContext translationContext, int sessionId, @NonNull TranslationManager translationManager, @NonNull Handler handler, + @Nullable ITranslationManager systemServerBinder, + @NonNull Consumer<Translator> callback) { + mContext = context; + mTranslationContext = translationContext; + mId = sessionId; + mManager = translationManager; + mHandler = handler; + mSystemServerBinder = systemServerBinder; + mServiceBinderReceiver = new ServiceBinderReceiver(this, callback); + + try { + mSystemServerBinder.onSessionCreated(mTranslationContext, mId, + mServiceBinderReceiver, mContext.getUserId()); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException calling startSession(): " + e); + } + } + + /** + * Create the Translator. + * + * @hide + */ + public Translator(@NonNull Context context, + @NonNull TranslationContext translationContext, int sessionId, + @NonNull TranslationManager translationManager, @NonNull Handler handler, @Nullable ITranslationManager systemServerBinder) { mContext = context; mTranslationContext = translationContext; @@ -214,6 +254,11 @@ public class Translator { } /** @hide */ + public TranslationContext getTranslationContext() { + return mTranslationContext; + } + + /** @hide */ public int getTranslatorId() { return mId; } diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java index 0425572a6f76..bdf217d644e2 100644 --- a/core/java/android/view/translation/UiTranslationController.java +++ b/core/java/android/view/translation/UiTranslationController.java @@ -451,13 +451,14 @@ public class UiTranslationController { int[] supportedFormats = getSupportedFormatsLocked(); ArrayList<ViewRootImpl> roots = WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken()); + TranslationCapability capability = + getTranslationCapability(translator.getTranslationContext()); mActivity.runOnUiThread(() -> { // traverse the hierarchy to collect ViewTranslationRequests for (int rootNum = 0; rootNum < roots.size(); rootNum++) { View rootView = roots.get(rootNum).getView(); - // TODO(b/183589662): call getTranslationCapabilities() for capability - rootView.dispatchRequestTranslation(viewIds, supportedFormats, /* capability */ - null, requests); + rootView.dispatchRequestTranslation(viewIds, supportedFormats, capability, + requests); } mWorkerHandler.sendMessage(PooledLambda.obtainMessage( UiTranslationController::sendTranslationRequest, @@ -487,6 +488,15 @@ public class UiTranslationController { return new int[] {TranslationSpec.DATA_FORMAT_TEXT}; } + private TranslationCapability getTranslationCapability(TranslationContext translationContext) { + // We only support text to text capability now, we will query real status from service when + // we support more translation capabilities. + return new TranslationCapability(TranslationCapability.STATE_ON_DEVICE, + translationContext.getSourceSpec(), + translationContext.getTargetSpec(), /* uiTranslationEnabled= */ true, + /* supportedTranslationFlags= */ 0); + } + private void findViewsTraversalByAutofillIds(IntArray sourceViewIds) { final ArrayList<ViewRootImpl> roots = WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken()); diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java index eefc7fdc7d77..541b4941c62e 100644 --- a/core/java/android/view/translation/UiTranslationManager.java +++ b/core/java/android/view/translation/UiTranslationManager.java @@ -119,15 +119,31 @@ public final class UiTranslationManager { } /** + * @deprecated Use {@link #startTranslation(TranslationSpec, TranslationSpec, List, ActivityId, + * UiTranslationSpec)} instead. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) + @Deprecated + @SystemApi + public void startTranslation(@NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec targetSpec, @NonNull List<AutofillId> viewIds, + @NonNull ActivityId activityId) { + startTranslation( + sourceSpec, targetSpec, viewIds, activityId, + new UiTranslationSpec.Builder().setShouldPadContentForCompat(true).build()); + } + + /** * Request ui translation for a given Views. * * @param sourceSpec {@link TranslationSpec} for the data to be translated. * @param targetSpec {@link TranslationSpec} for the translated data. * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated * @param activityId the identifier for the Activity which needs ui translation + * @param uiTranslationSpec configuration for translation of the specified views * @throws IllegalArgumentException if the no {@link View}'s {@link AutofillId} in the list - * @throws NullPointerException the sourceSpec, targetSpec, viewIds, activityId or - * {@link android.app.assist.ActivityId#getToken()} is {@code null} * * @hide */ @@ -135,19 +151,21 @@ public final class UiTranslationManager { @SystemApi public void startTranslation(@NonNull TranslationSpec sourceSpec, @NonNull TranslationSpec targetSpec, @NonNull List<AutofillId> viewIds, - @NonNull ActivityId activityId) { + @NonNull ActivityId activityId, @NonNull UiTranslationSpec uiTranslationSpec) { // TODO(b/177789967): Return result code or find a way to notify the status. Objects.requireNonNull(sourceSpec); Objects.requireNonNull(targetSpec); Objects.requireNonNull(viewIds); Objects.requireNonNull(activityId); Objects.requireNonNull(activityId.getToken()); + Objects.requireNonNull(uiTranslationSpec); if (viewIds.size() == 0) { throw new IllegalArgumentException("Invalid empty views: " + viewIds); } try { mService.updateUiTranslationState(STATE_UI_TRANSLATION_STARTED, sourceSpec, targetSpec, viewIds, activityId.getToken(), activityId.getTaskId(), + uiTranslationSpec, mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -172,7 +190,8 @@ public final class UiTranslationManager { Objects.requireNonNull(activityId.getToken()); mService.updateUiTranslationState(STATE_UI_TRANSLATION_FINISHED, null /* sourceSpec */, null /* targetSpec */, null /* viewIds */, - activityId.getToken(), activityId.getTaskId(), mContext.getUserId()); + activityId.getToken(), activityId.getTaskId(), null /* uiTranslationSpec */, + mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -196,7 +215,8 @@ public final class UiTranslationManager { Objects.requireNonNull(activityId.getToken()); mService.updateUiTranslationState(STATE_UI_TRANSLATION_PAUSED, null /* sourceSpec */, null /* targetSpec */, null /* viewIds */, - activityId.getToken(), activityId.getTaskId(), mContext.getUserId()); + activityId.getToken(), activityId.getTaskId(), null /* uiTranslationSpec */, + mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -220,7 +240,8 @@ public final class UiTranslationManager { Objects.requireNonNull(activityId.getToken()); mService.updateUiTranslationState(STATE_UI_TRANSLATION_RESUMED, null /* sourceSpec */, null /* targetSpec */, null /* viewIds */, - activityId.getToken(), activityId.getTaskId(), mContext.getUserId()); + activityId.getToken(), activityId.getTaskId(), null /* uiTranslationSpec */, + mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/telephony/java/android/telephony/ims/RcsConfig.aidl b/core/java/android/view/translation/UiTranslationSpec.aidl index cfd93fbe2edb..7fbeb66389a5 100644 --- a/telephony/java/android/telephony/ims/RcsConfig.aidl +++ b/core/java/android/view/translation/UiTranslationSpec.aidl @@ -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. @@ -14,6 +14,6 @@ * limitations under the License. */ -package android.telephony.ims; +package android.view.translation; -parcelable RcsConfig; +parcelable UiTranslationSpec; diff --git a/core/java/android/view/translation/UiTranslationSpec.java b/core/java/android/view/translation/UiTranslationSpec.java new file mode 100644 index 000000000000..b43dbce312c3 --- /dev/null +++ b/core/java/android/view/translation/UiTranslationSpec.java @@ -0,0 +1,248 @@ +/* + * 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.translation; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +/** + * Specifications for configuring UI translation. + * + * @hide + */ +@DataClass( + genBuilder = true, genEqualsHashCode = true, genHiddenConstDefs = true, genToString = true) +@DataClass.Suppress("isShouldPadContentForCompat") +@SystemApi +public final class UiTranslationSpec implements Parcelable { + + /** + * Whether the original content of the view should be directly modified to include padding that + * makes it the same size as the translated content. Defaults to {@code false}. + * <p> + * For {@link android.widget.TextView}, the system does not directly modify the original text, + * rather changes the displayed content using a + * {@link android.text.method.TransformationMethod}. + * This can cause issues in apps that do not account for TransformationMethods. For example, an + * app using DynamicLayout may use the calculated text offsets to operate on the original text, + * but this can be problematic when the layout was calculated on translated text with a + * different length. + * <p> + * If this is {@code true}, for a TextView the default implementation will append spaces to the + * text to make the length the same as the translated text. + */ + private boolean mShouldPadContentForCompat = false; + + /** + * Whether the original content of the view should be directly modified to include padding that + * makes it the same size as the translated content. + * <p> + * For {@link android.widget.TextView}, the system does not directly modify the original text, + * rather changes the displayed content using a + * {@link android.text.method.TransformationMethod}. + * This can cause issues in apps that do not account for TransformationMethods. For example, an + * app using DynamicLayout may use the calculated text offsets to operate on the original text, + * but this can be problematic when the layout was calculated on translated text with a + * different length. + * <p> + * If this is {@code true}, for a TextView the default implementation will append spaces to the + * text to make the length the same as the translated text. + */ + public boolean shouldPadContentForCompat() { + return mShouldPadContentForCompat; + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/UiTranslationSpec.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 */ UiTranslationSpec( + boolean shouldPadContentForCompat) { + this.mShouldPadContentForCompat = shouldPadContentForCompat; + + // onConstructed(); // You can define this method to get a callback + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "UiTranslationSpec { " + + "shouldPadContentForCompat = " + mShouldPadContentForCompat + + " }"; + } + + @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(UiTranslationSpec other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + UiTranslationSpec that = (UiTranslationSpec) o; + //noinspection PointlessBooleanExpression + return true + && mShouldPadContentForCompat == that.mShouldPadContentForCompat; + } + + @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 + Boolean.hashCode(mShouldPadContentForCompat); + 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) { ... } + + byte flg = 0; + if (mShouldPadContentForCompat) flg |= 0x1; + dest.writeByte(flg); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ UiTranslationSpec(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + boolean shouldPadContentForCompat = (flg & 0x1) != 0; + + this.mShouldPadContentForCompat = shouldPadContentForCompat; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<UiTranslationSpec> CREATOR + = new Parcelable.Creator<UiTranslationSpec>() { + @Override + public UiTranslationSpec[] newArray(int size) { + return new UiTranslationSpec[size]; + } + + @Override + public UiTranslationSpec createFromParcel(@NonNull Parcel in) { + return new UiTranslationSpec(in); + } + }; + + /** + * A builder for {@link UiTranslationSpec} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static final class Builder { + + private boolean mShouldPadContentForCompat; + + private long mBuilderFieldsSet = 0L; + + public Builder() { + } + + /** + * Whether the original content of the view should be directly modified to include padding that + * makes it the same size as the translated content. Defaults to {@code false}. + * <p> + * For {@link android.widget.TextView}, the system does not directly modify the original text, + * rather changes the displayed content using a + * {@link android.text.method.TransformationMethod}. + * This can cause issues in apps that do not account for TransformationMethods. For example, an + * app using DynamicLayout may use the calculated text offsets to operate on the original text, + * but this can be problematic when the layout was calculated on translated text with a + * different length. + * <p> + * If this is {@code true}, for a TextView the default implementation will append spaces to the + * text to make the length the same as the translated text. + */ + @DataClass.Generated.Member + public @NonNull Builder setShouldPadContentForCompat(boolean value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + mShouldPadContentForCompat = value; + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public @NonNull UiTranslationSpec build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; // Mark builder used + + if ((mBuilderFieldsSet & 0x1) == 0) { + mShouldPadContentForCompat = false; + } + UiTranslationSpec o = new UiTranslationSpec( + mShouldPadContentForCompat); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x2) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1619034161701L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/android/view/translation/UiTranslationSpec.java", + inputSignatures = "private boolean mShouldPadContentForCompat\npublic boolean shouldPadContentForCompat()\nclass UiTranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genToString=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java index c7eac6c72936..6b4956982d5f 100644 --- a/core/java/android/webkit/WebViewDelegate.java +++ b/core/java/android/webkit/WebViewDelegate.java @@ -16,6 +16,7 @@ package android.webkit; +import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -226,6 +227,7 @@ public final class WebViewDelegate { * WebViewChromiumFactoryProvider#create method was invoked. */ @NonNull + @ElapsedRealtimeLong public long[] getTimestamps() { return WebViewFactory.getTimestamps(); } diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index bc2b221d134a..5fc5b2972c65 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -83,16 +83,27 @@ public final class WebViewFactory { public @interface Timestamp { } + /** When the overall WebView provider load began. */ public static final int WEBVIEW_LOAD_START = 0; + /** Before creating the WebView APK Context. */ public static final int CREATE_CONTEXT_START = 1; + /** After creating the WebView APK Context. */ public static final int CREATE_CONTEXT_END = 2; + /** Before adding WebView assets to AssetManager. */ public static final int ADD_ASSETS_START = 3; + /** After adding WebView assets to AssetManager. */ public static final int ADD_ASSETS_END = 4; + /** Before creating the WebView ClassLoader. */ public static final int GET_CLASS_LOADER_START = 5; + /** After creating the WebView ClassLoader. */ public static final int GET_CLASS_LOADER_END = 6; + /** Before preloading the WebView native library. */ public static final int NATIVE_LOAD_START = 7; + /** After preloading the WebView native library. */ public static final int NATIVE_LOAD_END = 8; + /** Before looking up the WebView provider class. */ public static final int PROVIDER_CLASS_FOR_NAME_START = 9; + /** After looking up the WebView provider class. */ public static final int PROVIDER_CLASS_FOR_NAME_END = 10; private static final int TIMESTAMPS_SIZE = 11; diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 95a3dc788803..4d2d9e86f1a6 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -106,13 +106,13 @@ public class EdgeEffect { * The velocity threshold before the spring animation is considered settled. * The idea here is that velocity should be less than 0.1 pixel per second. */ - private static final double VELOCITY_THRESHOLD = 0.1; + private static final double VELOCITY_THRESHOLD = 0.01; /** * The value threshold before the spring animation is considered close enough to * the destination to be settled. This should be around 0.01 pixel. */ - private static final double VALUE_THRESHOLD = 0.01; + private static final double VALUE_THRESHOLD = 0.001; /** * The natural frequency of the stretch spring. diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 166411e7cecb..e06d5f00fb2c 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -259,6 +259,20 @@ public class Editor { // Used to highlight a word when it is corrected by the IME private CorrectionHighlighter mCorrectionHighlighter; + /** + * {@code true} when {@link TextView#setText(CharSequence, TextView.BufferType, boolean, int)} + * is being executed and {@link InputMethodManager#restartInput(View)} is scheduled to be + * called. + * + * <p>This is also used to avoid an unnecessary invocation of + * {@link InputMethodManager#updateSelection(View, int, int, int, int)} when + * {@link InputMethodManager#restartInput(View)} is scheduled to be called already + * See bug 186582769 for details.</p> + * + * <p>TODO(186582769): Come up with better way.</p> + */ + private boolean mHasPendingRestartInputForSetText = false; + InputContentType mInputContentType; InputMethodState mInputMethodState; @@ -1825,6 +1839,29 @@ public class Editor { } } + /** + * Called from {@link TextView#setText(CharSequence, TextView.BufferType, boolean, int)} to + * schedule {@link InputMethodManager#restartInput(View)}. + */ + void scheduleRestartInputForSetText() { + mHasPendingRestartInputForSetText = true; + } + + /** + * Called from {@link TextView#setText(CharSequence, TextView.BufferType, boolean, int)} to + * actually call {@link InputMethodManager#restartInput(View)} if it's scheduled. Does nothing + * otherwise. + */ + void maybeFireScheduledRestartInputForSetText() { + if (mHasPendingRestartInputForSetText) { + final InputMethodManager imm = getInputMethodManager(); + if (imm != null) { + imm.restartInput(mTextView); + } + mHasPendingRestartInputForSetText = false; + } + } + static final int EXTRACT_NOTHING = -2; static final int EXTRACT_UNKNOWN = -1; @@ -1958,7 +1995,8 @@ public class Editor { } private void sendUpdateSelection() { - if (null != mInputMethodState && mInputMethodState.mBatchEditNesting <= 0) { + if (null != mInputMethodState && mInputMethodState.mBatchEditNesting <= 0 + && !mHasPendingRestartInputForSetText) { final InputMethodManager imm = getInputMethodManager(); if (null != imm) { final int selectionStart = mTextView.getSelectionStart(); diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index 105c714930a2..e41893e37103 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -47,6 +47,7 @@ import android.view.animation.AnimationUtils; import android.view.inspector.InspectableProperty; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import java.util.List; @@ -86,19 +87,23 @@ public class HorizontalScrollView extends FrameLayout { * * Even though this field is practically final, we cannot make it final because there are apps * setting it via reflection and they need to keep working until they target Q. + * @hide */ @NonNull @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124053130) - private EdgeEffect mEdgeGlowLeft; + @VisibleForTesting + public EdgeEffect mEdgeGlowLeft; /** * Tracks the state of the bottom edge glow. * * Even though this field is practically final, we cannot make it final because there are apps * setting it via reflection and they need to keep working until they target Q. + * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124052619) - private EdgeEffect mEdgeGlowRight; + @VisibleForTesting + public EdgeEffect mEdgeGlowRight; /** * Position of the last motion event. @@ -706,8 +711,7 @@ public class HorizontalScrollView extends FrameLayout { if (getChildCount() == 0) { return false; } - if ((mIsBeingDragged = !mScroller.isFinished() || !mEdgeGlowRight.isFinished() - || !mEdgeGlowLeft.isFinished())) { + if (!mScroller.isFinished()) { final ViewParent parent = getParent(); if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); @@ -775,11 +779,8 @@ public class HorizontalScrollView extends FrameLayout { // Calling overScrollBy will call onOverScrolled, which // calls onScrollChanged if applicable. - if (overScrollBy(deltaX, 0, mScrollX, 0, range, 0, - mOverscrollDistance, 0, true)) { - // Break our velocity if we hit a scroll barrier. - mVelocityTracker.clear(); - } + overScrollBy(deltaX, 0, mScrollX, 0, range, 0, + mOverscrollDistance, 0, true); if (canOverscroll && deltaX != 0f) { final int pulledToX = oldX + deltaX; @@ -1738,23 +1739,31 @@ public class HorizontalScrollView extends FrameLayout { public void fling(int velocityX) { if (getChildCount() > 0) { int width = getWidth() - mPaddingRight - mPaddingLeft; - int right = getChildAt(0).getWidth(); + int right = getChildAt(0).getRight() - mPaddingLeft; - mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0, - Math.max(0, right - width), 0, 0, width/2, 0); + int maxScroll = Math.max(0, right - width); - final boolean movingRight = velocityX > 0; + if (mScrollX == 0 && !mEdgeGlowLeft.isFinished()) { + mEdgeGlowLeft.onAbsorb(-velocityX); + } else if (mScrollX == maxScroll && !mEdgeGlowRight.isFinished()) { + mEdgeGlowRight.onAbsorb(velocityX); + } else { + mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0, + maxScroll, 0, 0, width / 2, 0); - View currentFocused = findFocus(); - View newFocused = findFocusableViewInMyBounds(movingRight, - mScroller.getFinalX(), currentFocused); + final boolean movingRight = velocityX > 0; - if (newFocused == null) { - newFocused = this; - } + View currentFocused = findFocus(); + View newFocused = findFocusableViewInMyBounds(movingRight, + mScroller.getFinalX(), currentFocused); + + if (newFocused == null) { + newFocused = this; + } - if (newFocused != currentFocused) { - newFocused.requestFocus(movingRight ? View.FOCUS_RIGHT : View.FOCUS_LEFT); + if (newFocused != currentFocused) { + newFocused.requestFocus(movingRight ? View.FOCUS_RIGHT : View.FOCUS_LEFT); + } } postInvalidateOnAnimation(); diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index 18dd7995ae87..33890b80869d 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -939,6 +939,7 @@ public final class Magnifier { // The surface we allocate for the magnifier content + shadow. private final SurfaceSession mSurfaceSession; private final SurfaceControl mSurfaceControl; + private final SurfaceControl mBbqSurfaceControl; private final BLASTBufferQueue mBBQ; private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); private final Surface mSurface; @@ -1008,11 +1009,19 @@ public final class Magnifier { mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName("magnifier surface") .setFlags(SurfaceControl.HIDDEN) - .setBLASTLayer() + .setContainerLayer() .setParent(parentSurfaceControl) .setCallsite("InternalPopupWindow") .build(); - mBBQ = new BLASTBufferQueue("magnifier surface", mSurfaceControl, + mBbqSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) + .setName("magnifier surface bbq wrapper") + .setHidden(false) + .setBLASTLayer() + .setParent(mSurfaceControl) + .setCallsite("InternalPopupWindow") + .build(); + + mBBQ = new BLASTBufferQueue("magnifier surface", mBbqSurfaceControl, surfaceWidth, surfaceHeight, PixelFormat.TRANSLUCENT); mSurface = mBBQ.createSurface(); @@ -1073,7 +1082,7 @@ public final class Magnifier { } if (mContentHeight < contentHeight) { // Grows the surface height as necessary. - mBBQ.update(mSurfaceControl, mContentWidth, contentHeight, + mBBQ.update(mBbqSurfaceControl, mContentWidth, contentHeight, PixelFormat.TRANSLUCENT); mRenderer.setSurface(mSurface); @@ -1270,7 +1279,10 @@ public final class Magnifier { mRenderer.destroy(); mSurface.destroy(); mBBQ.destroy(); - new SurfaceControl.Transaction().remove(mSurfaceControl).apply(); + new SurfaceControl.Transaction() + .remove(mSurfaceControl) + .remove(mBbqSurfaceControl) + .apply(); mSurfaceSession.kill(); mHandler.removeCallbacks(mMagnifierUpdater); if (mBitmap != null) { diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index e47129e1d349..0dbdb8f6f0c4 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -1226,6 +1226,7 @@ public class RemoteViews implements Parcelable, Filter { return rect; } + @Nullable private static Class<?> getParameterType(int type) { switch (type) { case BaseReflectionAction.BOOLEAN: @@ -1267,6 +1268,7 @@ public class RemoteViews implements Parcelable, Filter { } } + @Nullable private MethodHandle getMethod(View view, String methodName, Class<?> paramType, boolean async) { MethodArgs result; @@ -1517,6 +1519,7 @@ public class RemoteViews implements Parcelable, Filter { } } + @Nullable public Bitmap getBitmapForId(int id) { if (id == -1 || id >= mBitmaps.size()) { return null; @@ -1864,8 +1867,9 @@ public class RemoteViews implements Parcelable, Filter { } } + @Nullable @Override - protected Object getParameterValue(View view) throws ActionException { + protected Object getParameterValue(@Nullable View view) throws ActionException { return this.value; } @@ -1904,8 +1908,11 @@ public class RemoteViews implements Parcelable, Filter { dest.writeInt(this.mResId); } + @Nullable @Override - protected Object getParameterValue(View view) throws ActionException { + protected Object getParameterValue(@Nullable View view) throws ActionException { + if (view == null) return null; + Resources resources = view.getContext().getResources(); try { switch (this.mResourceType) { @@ -2079,8 +2086,11 @@ public class RemoteViews implements Parcelable, Filter { dest.writeInt(this.mUnit); } + @Nullable @Override - protected Object getParameterValue(View view) throws ActionException { + protected Object getParameterValue(@Nullable View view) throws ActionException { + if (view == null) return null; + DisplayMetrics dm = view.getContext().getResources().getDisplayMetrics(); try { int data = TypedValue.createComplexDimension(this.mValue, this.mUnit); @@ -3592,6 +3602,9 @@ public class RemoteViews implements Parcelable, Filter { while (remoteViews.hasNext()) { RemoteViews view = remoteViews.next(); SizeF size = view.getIdealSize(); + if (size == null) { + throw new IllegalStateException("Expected RemoteViews to have ideal size"); + } float newViewArea = size.getWidth() * size.getHeight(); if (smallestView != null && !view.hasSameAppInfo(smallestView.mApplication)) { throw new IllegalArgumentException( @@ -5309,6 +5322,10 @@ public class RemoteViews implements Parcelable, Filter { float bestSqDist = Float.MAX_VALUE; for (RemoteViews layout : mSizedRemoteViews) { SizeF layoutSize = layout.getIdealSize(); + if (layoutSize == null) { + throw new IllegalStateException("Expected RemoteViews to have ideal size"); + } + if (fitsIn(layoutSize, widgetSize)) { if (bestFit == null) { bestFit = layout; @@ -5342,7 +5359,7 @@ public class RemoteViews implements Parcelable, Filter { */ public RemoteViews getRemoteViewsToApply(@NonNull Context context, @Nullable SizeF widgetSize) { - if (!hasSizedRemoteViews()) { + if (!hasSizedRemoteViews() || widgetSize == null) { // If there isn't multiple remote views, fall back on the previous methods. return getRemoteViewsToApply(context); } @@ -5419,7 +5436,7 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public View apply(Context context, ViewGroup parent, InteractionHandler handler, - @NonNull SizeF size, @Nullable ColorResources colorResources) { + @Nullable SizeF size, @Nullable ColorResources colorResources) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); View result = inflateView(context, rvToApply, parent, 0, colorResources); @@ -5431,7 +5448,7 @@ public class RemoteViews implements Parcelable, Filter { return inflateView(context, rv, parent, 0, null); } - private View inflateView(Context context, RemoteViews rv, ViewGroup parent, + private View inflateView(Context context, RemoteViews rv, @Nullable ViewGroup parent, @StyleRes int applyThemeResId, @Nullable ColorResources colorResources) { // RemoteViews may be built by an application installed in another // user. So build a context that loads resources from that user but @@ -5447,8 +5464,7 @@ public class RemoteViews implements Parcelable, Filter { if (applyThemeResId != 0) { inflationContext = new ContextThemeWrapper(inflationContext, applyThemeResId); } - LayoutInflater inflater = (LayoutInflater) - context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + LayoutInflater inflater = LayoutInflater.from(context); // Clone inflater so we load resources from correct context and // we don't add a filter to the static version returned by getSystemService. @@ -5576,6 +5592,7 @@ public class RemoteViews implements Parcelable, Filter { mResult = result; } + @Nullable @Override protected ViewTree doInBackground(Void... params) { try { @@ -5860,6 +5877,7 @@ public class RemoteViews implements Parcelable, Filter { * are in an array, the array's entries are 16 bytes each. We use this to work out the * location of all the positions of the various resources. */ + @Nullable private static byte[] createCompiledResourcesContent(Context context, SparseIntArray colorResources) throws IOException { byte[] content; @@ -5897,6 +5915,7 @@ public class RemoteViews implements Parcelable, Filter { * * @hide */ + @Nullable public static ColorResources create(Context context, SparseIntArray colorMapping) { try { byte[] contentBytes = createCompiledResourcesContent(context, colorMapping); @@ -6020,7 +6039,8 @@ public class RemoteViews implements Parcelable, Filter { } } - private static ApplicationInfo getApplicationInfo(String packageName, int userId) { + @Nullable + private static ApplicationInfo getApplicationInfo(@Nullable String packageName, int userId) { if (packageName == null) { return null; } @@ -6096,6 +6116,7 @@ public class RemoteViews implements Parcelable, Filter { } } + @Nullable public ViewTree findViewTreeById(@IdRes int id) { if (mRoot.getId() == id) { return this; @@ -6112,6 +6133,7 @@ public class RemoteViews implements Parcelable, Filter { return null; } + @Nullable public ViewTree findViewTreeParentOf(ViewTree child) { if (mChildren == null) { return null; @@ -6134,6 +6156,7 @@ public class RemoteViews implements Parcelable, Filter { createTree(); } + @Nullable public <T extends View> T findViewById(@IdRes int id) { if (mChildren == null) { return mRoot.findViewById(id); @@ -6391,6 +6414,8 @@ public class RemoteViews implements Parcelable, Filter { */ @Nullable private static AdapterView<?> getAdapterViewAncestor(@Nullable View view) { + if (view == null) return null; + View parent = (View) view.getParent(); // Break the for loop on the first encounter of: // 1) an AdapterView, diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 65f3da79afe0..3610eb47edbc 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -49,6 +49,7 @@ import android.view.animation.AnimationUtils; import android.view.inspector.InspectableProperty; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import java.util.List; @@ -95,20 +96,24 @@ public class ScrollView extends FrameLayout { * * Even though this field is practically final, we cannot make it final because there are apps * setting it via reflection and they need to keep working until they target Q. + * @hide */ @NonNull @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768600) - private EdgeEffect mEdgeGlowTop; + @VisibleForTesting + public EdgeEffect mEdgeGlowTop; /** * Tracks the state of the bottom edge glow. * * Even though this field is practically final, we cannot make it final because there are apps * setting it via reflection and they need to keep working until they target Q. + * @hide */ @NonNull @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769386) - private EdgeEffect mEdgeGlowBottom; + @VisibleForTesting + public EdgeEffect mEdgeGlowBottom; /** * Position of the last motion event. @@ -763,8 +768,7 @@ public class ScrollView extends FrameLayout { if (getChildCount() == 0) { return false; } - if ((mIsBeingDragged = !mScroller.isFinished() || !mEdgeGlowTop.isFinished() - || !mEdgeGlowBottom.isFinished())) { + if (!mScroller.isFinished()) { final ViewParent parent = getParent(); if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); @@ -1792,9 +1796,15 @@ public class ScrollView extends FrameLayout { final boolean canFling = (mScrollY > 0 || velocityY > 0) && (mScrollY < getScrollRange() || velocityY < 0); if (!dispatchNestedPreFling(0, velocityY)) { - dispatchNestedFling(0, velocityY, canFling); + final boolean consumed = dispatchNestedFling(0, velocityY, canFling); if (canFling) { fling(velocityY); + } else if (!consumed) { + if (!mEdgeGlowTop.isFinished()) { + mEdgeGlowTop.onAbsorb(-velocityY); + } else if (!mEdgeGlowBottom.isFinished()) { + mEdgeGlowBottom.onAbsorb(velocityY); + } } } } diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index a16c1519e4d0..7c04b1cc195b 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -461,7 +461,7 @@ public class SpellChecker implements SpellCheckerSessionListener { @Override public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) { final Editable editable = (Editable) mTextView.getText(); - + final int sentenceLength = editable.length(); for (int i = 0; i < results.length; ++i) { final SentenceSuggestionsInfo ssi = results[i]; if (ssi == null) { @@ -475,6 +475,9 @@ public class SpellChecker implements SpellCheckerSessionListener { } final int offset = ssi.getOffsetAt(j); final int length = ssi.getLengthAt(j); + if (offset < 0 || offset + length > sentenceLength) { + continue; + } final SpellCheckSpan scs = onGetSuggestionsInternal( suggestionsInfo, offset, length); if (spellCheckSpan == null && scs != null) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 07a9a5fad6e2..1a37b595287d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -6285,11 +6285,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener || needEditableForNotification) { createEditorIfNeeded(); mEditor.forgetUndoRedo(); + mEditor.scheduleRestartInputForSetText(); Editable t = mEditableFactory.newEditable(text); text = t; setFilters(t, mFilters); - InputMethodManager imm = getInputMethodManager(); - if (imm != null) imm.restartInput(this); } else if (precomputed != null) { if (mTextDir == null) { mTextDir = getTextDirectionHeuristic(); @@ -6408,8 +6407,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener notifyListeningManagersAfterTextChanged(); } - // SelectionModifierCursorController depends on textCanBeSelected, which depends on text - if (mEditor != null) mEditor.prepareCursorControllers(); + if (mEditor != null) { + // SelectionModifierCursorController depends on textCanBeSelected, which depends on text + mEditor.prepareCursorControllers(); + + mEditor.maybeFireScheduledRestartInputForSetText(); + } } /** diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java index 18f29ae8eeca..7d222dbe7bd2 100644 --- a/core/java/android/window/SplashScreen.java +++ b/core/java/android/window/SplashScreen.java @@ -17,12 +17,17 @@ package android.window; import android.annotation.NonNull; +import android.annotation.StyleRes; import android.annotation.SuppressLint; import android.annotation.UiThread; import android.app.Activity; import android.app.ActivityThread; +import android.app.AppGlobals; import android.content.Context; +import android.content.res.Resources; import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; import android.util.Singleton; import android.util.Slog; @@ -60,6 +65,17 @@ public interface SplashScreen { */ void clearOnExitAnimationListener(); + + /** + * Overrides the theme used for the {@link SplashScreen}s of this application. + * <p> + * By default, the {@link SplashScreen} uses the theme set in the manifest. This method + * overrides and persists the theme used for the {@link SplashScreen} of this application. + * <p> + * To reset to the default theme, set this the themeId to {@link Resources#ID_NULL}. + */ + void setSplashScreenTheme(@StyleRes int themeId); + /** * Listens for the splash screen exit event. */ @@ -84,6 +100,8 @@ public interface SplashScreen { * @hide */ class SplashScreenImpl implements SplashScreen { + private static final String TAG = "SplashScreenImpl"; + private OnExitAnimationListener mExitAnimationListener; private final IBinder mActivityToken; private final SplashScreenManagerGlobal mGlobal; @@ -119,6 +137,29 @@ public interface SplashScreen { mGlobal.removeImpl(this); } } + + public void setSplashScreenTheme(@StyleRes int themeId) { + if (mActivityToken == null) { + Log.w(TAG, "Couldn't persist the starting theme. This instance is not an Activity"); + return; + } + + Activity activity = ActivityThread.currentActivityThread().getActivity( + mActivityToken); + if (activity == null) { + return; + } + String themeName = themeId != Resources.ID_NULL + ? activity.getResources().getResourceName(themeId) : null; + + try { + AppGlobals.getPackageManager().setSplashScreenTheme( + activity.getComponentName().getPackageName(), + themeName, activity.getUserId()); + } catch (RemoteException e) { + Log.w(TAG, "Couldn't persist the starting theme", e); + } + } } /** diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 26a6f0dcf470..c0af57214e5e 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -109,8 +109,8 @@ public final class WindowContainerTransaction implements Parcelable { } /** - * Notify activities within the hierarchy of a container that they have entered picture-in-picture - * mode with the given bounds. + * Notify {@link com.android.server.wm.PinnedTaskController} that the picture-in-picture task + * has finished the enter animation with the given bounds. */ @NonNull public WindowContainerTransaction scheduleFinishEnterPip( @@ -339,6 +339,33 @@ public final class WindowContainerTransaction implements Parcelable { } /** + * Sets the container as launch adjacent flag root. Task starting with + * {@link FLAG_ACTIVITY_LAUNCH_ADJACENT} will be launching to. + * + * @hide + */ + @NonNull + public WindowContainerTransaction setLaunchAdjacentFlagRoot( + @NonNull WindowContainerToken container) { + mHierarchyOps.add(HierarchyOp.createForSetLaunchAdjacentFlagRoot(container.asBinder(), + false /* clearRoot */)); + return this; + } + + /** + * Clears launch adjacent flag root for the display area of passing container. + * + * @hide + */ + @NonNull + public WindowContainerTransaction clearLaunchAdjacentFlagRoot( + @NonNull WindowContainerToken container) { + mHierarchyOps.add(HierarchyOp.createForSetLaunchAdjacentFlagRoot(container.asBinder(), + true /* clearRoot */)); + return this; + } + + /** * Starts a task by id. The task is expected to already exist (eg. as a recent task). * @param taskId Id of task to start. * @param options bundle containing ActivityOptions for the task's top activity. @@ -677,6 +704,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT = 3; public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS = 4; public static final int HIERARCHY_OP_TYPE_LAUNCH_TASK = 5; + public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT = 6; // The following key(s) are for use with mLaunchOptions: // When launching a task (eg. from recents), this is the taskId to be launched. @@ -734,6 +762,14 @@ public final class WindowContainerTransaction implements Parcelable { fullOptions); } + /** Create a hierarchy op for setting launch adjacent flag root. */ + public static HierarchyOp createForSetLaunchAdjacentFlagRoot(IBinder container, + boolean clearRoot) { + return new HierarchyOp(HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT, container, null, + null, null, clearRoot, null); + } + + private HierarchyOp(int type, @Nullable IBinder container, @Nullable IBinder reparent, int[] windowingModes, int[] activityTypes, boolean toTop, @Nullable Bundle launchOptions) { @@ -829,6 +865,9 @@ public final class WindowContainerTransaction implements Parcelable { + " adjacentRoot=" + mReparent + "}"; case HIERARCHY_OP_TYPE_LAUNCH_TASK: return "{LaunchTask: " + mLaunchOptions + "}"; + case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: + return "{SetAdjacentFlagRoot: container=" + mContainer + " clearRoot=" + mToTop + + "}"; default: return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent + " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java index 9d06bb92b205..f2d91ba30842 100644 --- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java @@ -203,34 +203,33 @@ public final class AccessibilityTargetHelper { final InvisibleToggleAllowListingFeatureTarget magnification = new InvisibleToggleAllowListingFeatureTarget(context, - shortcutType, - isShortcutContained(context, shortcutType, MAGNIFICATION_CONTROLLER_NAME), - MAGNIFICATION_CONTROLLER_NAME, - context.getString(R.string.accessibility_magnification_chooser_text), - context.getDrawable(R.drawable.ic_accessibility_magnification), - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED); + shortcutType, + isShortcutContained(context, shortcutType, MAGNIFICATION_CONTROLLER_NAME), + MAGNIFICATION_CONTROLLER_NAME, + context.getString(R.string.accessibility_magnification_chooser_text), + context.getDrawable(R.drawable.ic_accessibility_magnification), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED); final ToggleAllowListingFeatureTarget daltonizer = new ToggleAllowListingFeatureTarget(context, - shortcutType, - isShortcutContained(context, shortcutType, - DALTONIZER_COMPONENT_NAME.flattenToString()), - DALTONIZER_COMPONENT_NAME.flattenToString(), - context.getString(R.string.color_correction_feature_name), - context.getDrawable(R.drawable.ic_accessibility_color_correction), - Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED); + shortcutType, + isShortcutContained(context, shortcutType, + DALTONIZER_COMPONENT_NAME.flattenToString()), + DALTONIZER_COMPONENT_NAME.flattenToString(), + context.getString(R.string.color_correction_feature_name), + context.getDrawable(R.drawable.ic_accessibility_color_correction), + Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED); final ToggleAllowListingFeatureTarget colorInversion = new ToggleAllowListingFeatureTarget(context, - shortcutType, - isShortcutContained(context, shortcutType, - COLOR_INVERSION_COMPONENT_NAME.flattenToString()), - COLOR_INVERSION_COMPONENT_NAME.flattenToString(), - context.getString(R.string.color_inversion_feature_name), - context.getDrawable(R.drawable.ic_accessibility_color_inversion), - Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); - - // TODO: Update with shortcut icon + shortcutType, + isShortcutContained(context, shortcutType, + COLOR_INVERSION_COMPONENT_NAME.flattenToString()), + COLOR_INVERSION_COMPONENT_NAME.flattenToString(), + context.getString(R.string.color_inversion_feature_name), + context.getDrawable(R.drawable.ic_accessibility_color_inversion), + Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); + final ToggleAllowListingFeatureTarget reduceBrightColors = new ToggleAllowListingFeatureTarget(context, shortcutType, @@ -238,7 +237,7 @@ public final class AccessibilityTargetHelper { REDUCE_BRIGHT_COLORS_COMPONENT_NAME.flattenToString()), REDUCE_BRIGHT_COLORS_COMPONENT_NAME.flattenToString(), context.getString(R.string.reduce_bright_colors_feature_name), - null, + context.getDrawable(R.drawable.ic_accessibility_reduce_bright_colors), Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED); targets.add(magnification); diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java index 8fef8378f33c..4133c4d41aaa 100644 --- a/core/java/com/android/internal/app/procstats/AssociationState.java +++ b/core/java/com/android/internal/app/procstats/AssociationState.java @@ -16,8 +16,10 @@ package com.android.internal.app.procstats; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; +import android.os.Parcelable; import android.os.SystemClock; import android.os.UserHandle; import android.service.procstats.PackageAssociationProcessStatsProto; @@ -54,7 +56,14 @@ public final class AssociationState { private int mTotalActiveCount; private long mTotalActiveDuration; - public final class SourceState { + /** + * The state of the source process of an association. + */ + public static final class SourceState implements Parcelable { + private @NonNull final ProcessStats mProcessStats; + private @Nullable final AssociationState mAssociationState; + private @Nullable final ProcessState mTargetProcess; + private @Nullable SourceState mCommonSourceState; final SourceKey mKey; int mProcStateSeq = -1; int mProcState = ProcessStats.STATE_NOTHING; @@ -64,18 +73,24 @@ public final class AssociationState { long mStartUptime; long mDuration; long mTrackingUptime; + int mActiveNesting; int mActiveCount; int mActiveProcState = ProcessStats.STATE_NOTHING; long mActiveStartUptime; long mActiveDuration; DurationsTable mActiveDurations; - SourceState(SourceKey key) { + SourceState(@NonNull ProcessStats processStats, @Nullable AssociationState associationState, + @NonNull ProcessState targetProcess, SourceKey key) { + mProcessStats = processStats; + mAssociationState = associationState; + mTargetProcess = targetProcess; mKey = key; } + @Nullable public AssociationState getAssociationState() { - return AssociationState.this; + return mAssociationState; } public String getProcessName() { @@ -86,7 +101,20 @@ public final class AssociationState { return mKey.mUid; } + @Nullable + private SourceState getCommonSourceState(boolean createIfNeeded) { + if (mCommonSourceState == null) { + if (createIfNeeded) { + mCommonSourceState = mTargetProcess.getOrCreateSourceState(mKey); + } else { + Slog.wtf(TAG, "Unable to find common source state for " + mKey.mProcess); + } + } + return mCommonSourceState; + } + public void trackProcState(int procState, int seq, long now) { + final int processState = procState; procState = ProcessState.PROCESS_STATE_TO_STATE[procState]; if (seq != mProcStateSeq) { mProcStateSeq = seq; @@ -102,30 +130,81 @@ public final class AssociationState { if (!mInTrackingList) { mInTrackingList = true; mTrackingUptime = now; - mProcessStats.mTrackingAssociations.add(this); + if (mAssociationState != null) { + mProcessStats.mTrackingAssociations.add(this); + } + } + } + if (mAssociationState != null) { + final SourceState commonSource = getCommonSourceState(true); + if (commonSource != null) { + commonSource.trackProcState(processState, seq, now); } } } + long start() { + final long now = start(-1); + if (mAssociationState != null) { + final SourceState commonSource = getCommonSourceState(true); + if (commonSource != null) { + commonSource.start(now); + } + } + return now; + } + + long start(long now) { + mNesting++; + if (mNesting == 1) { + if (now < 0) { + now = SystemClock.uptimeMillis(); + } + mCount++; + mStartUptime = now; + } + return now; + } + public void stop() { + final long now = stop(-1); + if (mAssociationState != null) { + final SourceState commonSource = getCommonSourceState(false); + if (commonSource != null) { + commonSource.stop(now); + } + } + } + + long stop(long now) { mNesting--; if (mNesting == 0) { - final long now = SystemClock.uptimeMillis(); + if (now < 0) { + now = SystemClock.uptimeMillis(); + } mDuration += now - mStartUptime; stopTracking(now); } + return now; } void startActive(long now) { + boolean startActive = false; if (mInTrackingList) { if (mActiveStartUptime == 0) { mActiveStartUptime = now; + mActiveNesting++; mActiveCount++; - AssociationState.this.mTotalActiveNesting++; - if (AssociationState.this.mTotalActiveNesting == 1) { - AssociationState.this.mTotalActiveCount++; - AssociationState.this.mTotalActiveStartUptime = now; + startActive = true; + if (mAssociationState != null) { + mAssociationState.mTotalActiveNesting++; + if (mAssociationState.mTotalActiveNesting == 1) { + mAssociationState.mTotalActiveCount++; + mAssociationState.mTotalActiveStartUptime = now; + } } + } else if (mAssociationState == null) { + mActiveNesting++; } if (mActiveProcState != mProcState) { if (mActiveProcState != ProcessStats.STATE_NOTHING) { @@ -133,6 +212,9 @@ public final class AssociationState { // so far and switch tracking to the new proc state. final long addedDuration = mActiveDuration + now - mActiveStartUptime; mActiveStartUptime = now; + if (mAssociationState != null) { + startActive = true; + } if (addedDuration != 0) { if (mActiveDurations == null) { makeDurations(); @@ -146,68 +228,233 @@ public final class AssociationState { } else { Slog.wtf(TAG, "startActive while not tracking: " + this); } + if (mAssociationState != null) { + final SourceState commonSource = getCommonSourceState(true); + if (commonSource != null && startActive) { + commonSource.startActive(now); + } + } } void stopActive(long now) { + boolean stopActive = false; if (mActiveStartUptime != 0) { - if (!mInTrackingList) { + if (!mInTrackingList && mAssociationState != null) { Slog.wtf(TAG, "stopActive while not tracking: " + this); } + mActiveNesting--; final long addedDuration = now - mActiveStartUptime; - mActiveStartUptime = 0; + mActiveStartUptime = mAssociationState != null || mActiveNesting == 0 ? 0 : now; + stopActive = mActiveStartUptime == 0; if (mActiveDurations != null) { mActiveDurations.addDuration(mActiveProcState, addedDuration); } else { mActiveDuration += addedDuration; } - AssociationState.this.mTotalActiveNesting--; - if (AssociationState.this.mTotalActiveNesting == 0) { - AssociationState.this.mTotalActiveDuration += now - - AssociationState.this.mTotalActiveStartUptime; - AssociationState.this.mTotalActiveStartUptime = 0; - if (VALIDATE_TIMES) { - if (mActiveDuration > AssociationState.this.mTotalActiveDuration) { - RuntimeException ex = new RuntimeException(); - ex.fillInStackTrace(); - Slog.w(TAG, "Source act duration " + mActiveDurations - + " exceeds total " + AssociationState.this.mTotalActiveDuration - + " in procstate " + mActiveProcState + " in source " - + mKey.mProcess + " to assoc " - + AssociationState.this.mName, ex); - } + if (mAssociationState != null) { + mAssociationState.mTotalActiveNesting--; + if (mAssociationState.mTotalActiveNesting == 0) { + mAssociationState.mTotalActiveDuration += now + - mAssociationState.mTotalActiveStartUptime; + mAssociationState.mTotalActiveStartUptime = 0; + if (VALIDATE_TIMES) { + if (mActiveDuration > mAssociationState.mTotalActiveDuration) { + RuntimeException ex = new RuntimeException(); + ex.fillInStackTrace(); + Slog.w(TAG, "Source act duration " + mActiveDurations + + " exceeds total " + mAssociationState.mTotalActiveDuration + + " in procstate " + mActiveProcState + " in source " + + mKey.mProcess + " to assoc " + + mAssociationState.mName, ex); + } + } } } } + + if (mAssociationState != null) { + final SourceState commonSource = getCommonSourceState(false); + if (commonSource != null && stopActive) { + commonSource.stopActive(now); + } + } + } + + boolean stopActiveIfNecessary(int curSeq, long now) { + if (mProcStateSeq != curSeq || mProcState >= ProcessStats.STATE_HOME) { + // If this association did not get touched the last time we computed + // process states, or its state ended up down in cached, then we no + // longer have a reason to track it at all. + stopActive(now); + stopTrackingProcState(); + return true; + } + return false; + } + + private void stopTrackingProcState() { + mInTrackingList = false; + mProcState = ProcessStats.STATE_NOTHING; + if (mAssociationState != null) { + final SourceState commonSource = getCommonSourceState(false); + if (commonSource != null) { + commonSource.stopTrackingProcState(); + } + } + } + + boolean isInUse() { + return mNesting > 0; + } + + void resetSafely(long now) { + if (isInUse()) { + mCount = 1; + mStartUptime = now; + mDuration = 0; + if (mActiveStartUptime > 0) { + mActiveCount = 1; + mActiveStartUptime = now; + } else { + mActiveCount = 0; + } + mActiveDuration = 0; + mActiveDurations = null; + } + } + + void commitStateTime(long nowUptime) { + if (mNesting > 0) { + mDuration += nowUptime - mStartUptime; + mStartUptime = nowUptime; + } + if (mActiveStartUptime > 0) { + final long addedDuration = nowUptime - mActiveStartUptime; + mActiveStartUptime = nowUptime; + if (mActiveDurations != null) { + mActiveDurations.addDuration(mActiveProcState, addedDuration); + } else { + mActiveDuration += addedDuration; + } + } } void makeDurations() { mActiveDurations = new DurationsTable(mProcessStats.mTableData); } - void stopTracking(long now) { - AssociationState.this.mTotalNesting--; - if (AssociationState.this.mTotalNesting == 0) { - AssociationState.this.mTotalDuration += now - - AssociationState.this.mTotalStartUptime; + private void stopTracking(long now) { + if (mAssociationState != null) { + mAssociationState.mTotalNesting--; + if (mAssociationState.mTotalNesting == 0) { + mAssociationState.mTotalDuration += now + - mAssociationState.mTotalStartUptime; + } } stopActive(now); if (mInTrackingList) { mInTrackingList = false; mProcState = ProcessStats.STATE_NOTHING; - // Do a manual search for where to remove, since these objects will typically - // be towards the end of the array. - final ArrayList<SourceState> list = mProcessStats.mTrackingAssociations; - for (int i = list.size() - 1; i >= 0; i--) { - if (list.get(i) == this) { - list.remove(i); - return; + if (mAssociationState != null) { + // Do a manual search for where to remove, since these objects will typically + // be towards the end of the array. + final ArrayList<SourceState> list = mProcessStats.mTrackingAssociations; + for (int i = list.size() - 1; i >= 0; i--) { + if (list.get(i) == this) { + list.remove(i); + return; + } } + Slog.wtf(TAG, "Stop tracking didn't find in tracking list: " + this); } - Slog.wtf(TAG, "Stop tracking didn't find in tracking list: " + this); } } + void add(SourceState otherSrc) { + mCount += otherSrc.mCount; + mDuration += otherSrc.mDuration; + mActiveCount += otherSrc.mActiveCount; + if (otherSrc.mActiveDuration != 0 || otherSrc.mActiveDurations != null) { + // Only need to do anything if the other one has some duration data. + if (mActiveDurations != null) { + // If the target already has multiple durations, just add in whatever + // we have in the other. + if (otherSrc.mActiveDurations != null) { + mActiveDurations.addDurations(otherSrc.mActiveDurations); + } else { + mActiveDurations.addDuration(otherSrc.mActiveProcState, + otherSrc.mActiveDuration); + } + } else if (otherSrc.mActiveDurations != null) { + // The other one has multiple durations, but we don't. Expand to + // multiple durations and copy over. + makeDurations(); + mActiveDurations.addDurations(otherSrc.mActiveDurations); + if (mActiveDuration != 0) { + mActiveDurations.addDuration(mActiveProcState, mActiveDuration); + mActiveDuration = 0; + mActiveProcState = ProcessStats.STATE_NOTHING; + } + } else if (mActiveDuration != 0) { + // Both have a single inline duration... we can either add them together, + // or need to expand to multiple durations. + if (mActiveProcState == otherSrc.mActiveProcState) { + mActiveDuration += otherSrc.mActiveDuration; + } else { + // The two have durations with different proc states, need to turn + // in to multiple durations. + makeDurations(); + mActiveDurations.addDuration(mActiveProcState, mActiveDuration); + mActiveDurations.addDuration(otherSrc.mActiveProcState, + otherSrc.mActiveDuration); + mActiveDuration = 0; + mActiveProcState = ProcessStats.STATE_NOTHING; + } + } else { + // The other one has a duration, and we know the target doesn't. Copy over. + mActiveProcState = otherSrc.mActiveProcState; + mActiveDuration = otherSrc.mActiveDuration; + } + } + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mCount); + out.writeLong(mDuration); + out.writeInt(mActiveCount); + if (mActiveDurations != null) { + out.writeInt(1); + mActiveDurations.writeToParcel(out); + } else { + out.writeInt(0); + out.writeInt(mActiveProcState); + out.writeLong(mActiveDuration); + } + } + + @Override + public int describeContents() { + return 0; + } + + String readFromParcel(Parcel in) { + mCount = in.readInt(); + mDuration = in.readLong(); + mActiveCount = in.readInt(); + if (in.readInt() != 0) { + makeDurations(); + if (!mActiveDurations.readFromParcel(in)) { + return "Duration table corrupt: " + mKey + " <- " + toString(); + } + } else { + mActiveProcState = in.readInt(); + mActiveDuration = in.readLong(); + } + return null; + } + @Override public String toString() { StringBuilder sb = new StringBuilder(64); @@ -222,7 +469,7 @@ public final class AssociationState { } } - public final class SourceDumpContainer { + static final class SourceDumpContainer { public final SourceState mState; public long mTotalTime; public long mActiveTime; @@ -256,6 +503,18 @@ public final class AssociationState { mPackage = pkg; } + SourceKey(ProcessStats stats, Parcel in, int parcelVersion) { + mUid = in.readInt(); + mProcess = stats.readCommonString(in, parcelVersion); + mPackage = stats.readCommonString(in, parcelVersion); + } + + void writeToParcel(ProcessStats stats, Parcel out) { + out.writeInt(mUid); + stats.writeCommonString(out, mProcess); + stats.writeCommonString(out, mPackage); + } + public boolean equals(Object o) { if (!(o instanceof SourceKey)) { return false; @@ -347,14 +606,11 @@ public final class AssociationState { } if (src == null) { SourceKey key = new SourceKey(uid, processName, packageName); - src = new SourceState(key); + src = new SourceState(mProcessStats, this, mProc, key); mSources.put(key, src); } - src.mNesting++; - if (src.mNesting == 1) { - final long now = SystemClock.uptimeMillis(); - src.mCount++; - src.mStartUptime = now; + final long now = src.start(); + if (now > 0) { mTotalNesting++; if (mTotalNesting == 1) { mTotalCount++; @@ -376,7 +632,7 @@ public final class AssociationState { SourceState mySrc = mSources.get(key); boolean newSrc = false; if (mySrc == null) { - mySrc = new SourceState(key); + mySrc = new SourceState(mProcessStats, this, mProc, key); mSources.put(key, mySrc); newSrc = true; } @@ -412,53 +668,7 @@ public final class AssociationState { } } } - mySrc.mCount += otherSrc.mCount; - mySrc.mDuration += otherSrc.mDuration; - mySrc.mActiveCount += otherSrc.mActiveCount; - if (otherSrc.mActiveDuration != 0 || otherSrc.mActiveDurations != null) { - // Only need to do anything if the other one has some duration data. - if (mySrc.mActiveDurations != null) { - // If the target already has multiple durations, just add in whatever - // we have in the other. - if (otherSrc.mActiveDurations != null) { - mySrc.mActiveDurations.addDurations(otherSrc.mActiveDurations); - } else { - mySrc.mActiveDurations.addDuration(otherSrc.mActiveProcState, - otherSrc.mActiveDuration); - } - } else if (otherSrc.mActiveDurations != null) { - // The other one has multiple durations, but we don't. Expand to - // multiple durations and copy over. - mySrc.makeDurations(); - mySrc.mActiveDurations.addDurations(otherSrc.mActiveDurations); - if (mySrc.mActiveDuration != 0) { - mySrc.mActiveDurations.addDuration(mySrc.mActiveProcState, - mySrc.mActiveDuration); - mySrc.mActiveDuration = 0; - mySrc.mActiveProcState = ProcessStats.STATE_NOTHING; - } - } else if (mySrc.mActiveDuration != 0) { - // Both have a single inline duration... we can either add them together, - // or need to expand to multiple durations. - if (mySrc.mActiveProcState == otherSrc.mActiveProcState) { - mySrc.mActiveDuration += otherSrc.mActiveDuration; - } else { - // The two have durations with different proc states, need to turn - // in to multiple durations. - mySrc.makeDurations(); - mySrc.mActiveDurations.addDuration(mySrc.mActiveProcState, - mySrc.mActiveDuration); - mySrc.mActiveDurations.addDuration(otherSrc.mActiveProcState, - otherSrc.mActiveDuration); - mySrc.mActiveDuration = 0; - mySrc.mActiveProcState = ProcessStats.STATE_NOTHING; - } - } else { - // The other one has a duration, and we know the target doesn't. Copy over. - mySrc.mActiveProcState = otherSrc.mActiveProcState; - mySrc.mActiveDuration = otherSrc.mActiveDuration; - } - } + mySrc.add(otherSrc); } } @@ -474,18 +684,8 @@ public final class AssociationState { // We have some active sources... clear out everything but those. for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) { SourceState src = mSources.valueAt(isrc); - if (src.mNesting > 0) { - src.mCount = 1; - src.mStartUptime = now; - src.mDuration = 0; - if (src.mActiveStartUptime > 0) { - src.mActiveCount = 1; - src.mActiveStartUptime = now; - } else { - src.mActiveCount = 0; - } - src.mActiveDuration = 0; - src.mActiveDurations = null; + if (src.isInUse()) { + src.resetSafely(now); } else { mSources.removeAt(isrc); } @@ -512,20 +712,8 @@ public final class AssociationState { for (int isrc = 0; isrc < NSRC; isrc++) { final SourceKey key = mSources.keyAt(isrc); final SourceState src = mSources.valueAt(isrc); - out.writeInt(key.mUid); - stats.writeCommonString(out, key.mProcess); - stats.writeCommonString(out, key.mPackage); - out.writeInt(src.mCount); - out.writeLong(src.mDuration); - out.writeInt(src.mActiveCount); - if (src.mActiveDurations != null) { - out.writeInt(1); - src.mActiveDurations.writeToParcel(out); - } else { - out.writeInt(0); - out.writeInt(src.mActiveProcState); - out.writeLong(src.mActiveDuration); - } + key.writeToParcel(stats, out); + src.writeToParcel(out, 0); } } @@ -543,22 +731,11 @@ public final class AssociationState { return "Association with bad src count: " + NSRC; } for (int isrc = 0; isrc < NSRC; isrc++) { - final int uid = in.readInt(); - final String procName = stats.readCommonString(in, parcelVersion); - final String pkgName = stats.readCommonString(in, parcelVersion); - final SourceKey key = new SourceKey(uid, procName, pkgName); - final SourceState src = new SourceState(key); - src.mCount = in.readInt(); - src.mDuration = in.readLong(); - src.mActiveCount = in.readInt(); - if (in.readInt() != 0) { - src.makeDurations(); - if (!src.mActiveDurations.readFromParcel(in)) { - return "Duration table corrupt: " + key + " <- " + src; - } - } else { - src.mActiveProcState = in.readInt(); - src.mActiveDuration = in.readLong(); + final SourceKey key = new SourceKey(stats, in, parcelVersion); + final SourceState src = new SourceState(mProcessStats, this, mProc, key); + final String errMsg = src.readFromParcel(in); + if (errMsg != null) { + return errMsg; } if (VALIDATE_TIMES) { if (src.mDuration > mTotalDuration) { @@ -585,19 +762,7 @@ public final class AssociationState { if (isInUse()) { for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) { SourceState src = mSources.valueAt(isrc); - if (src.mNesting > 0) { - src.mDuration += nowUptime - src.mStartUptime; - src.mStartUptime = nowUptime; - } - if (src.mActiveStartUptime > 0) { - final long addedDuration = nowUptime - src.mActiveStartUptime; - src.mActiveStartUptime = nowUptime; - if (src.mActiveDurations != null) { - src.mActiveDurations.addDuration(src.mActiveProcState, addedDuration); - } else { - src.mActiveDuration += addedDuration; - } - } + src.commitStateTime(nowUptime); } if (mTotalNesting > 0) { mTotalDuration += nowUptime - mTotalStartUptime; @@ -644,12 +809,12 @@ public final class AssociationState { return 0; }; - public ArrayList<Pair<SourceKey, SourceDumpContainer>> createSortedAssociations(long now, - long totalTime) { - final int NSRC = mSources.size(); - ArrayList<Pair<SourceKey, SourceDumpContainer>> sources = new ArrayList<>(NSRC); - for (int isrc = 0; isrc < NSRC; isrc++) { - final SourceState src = mSources.valueAt(isrc); + static ArrayList<Pair<SourceKey, SourceDumpContainer>> createSortedAssociations(long now, + long totalTime, ArrayMap<SourceKey, SourceState> inSources) { + final int numOfSources = inSources.size(); + ArrayList<Pair<SourceKey, SourceDumpContainer>> sources = new ArrayList<>(numOfSources); + for (int isrc = 0; isrc < numOfSources; isrc++) { + final SourceState src = inSources.valueAt(isrc); final SourceDumpContainer cont = new SourceDumpContainer(src); long duration = src.mDuration; if (src.mNesting > 0) { @@ -660,7 +825,7 @@ public final class AssociationState { if (cont.mActiveTime < 0) { cont.mActiveTime = -cont.mActiveTime; } - sources.add(new Pair<>(mSources.keyAt(isrc), cont)); + sources.add(new Pair<>(inSources.keyAt(isrc), cont)); } Collections.sort(sources, ASSOCIATION_COMPARATOR); return sources; @@ -722,6 +887,14 @@ public final class AssociationState { TimeUtils.formatDuration(mTotalStartUptime, now, pw); pw.println(); } + + dumpSources(pw, prefix, prefixInner, prefixInnerInner, sources, now, totalTime, + reqPackage, dumpDetails, dumpAll); + } + + static void dumpSources(PrintWriter pw, String prefix, String prefixInner, + String prefixInnerInner, ArrayList<Pair<SourceKey, SourceDumpContainer>> sources, + long now, long totalTime, String reqPackage, boolean dumpDetails, boolean dumpAll) { final int NSRC = sources.size(); for (int isrc = 0; isrc < NSRC; isrc++) { final SourceKey key = sources.get(isrc).first; @@ -826,7 +999,7 @@ public final class AssociationState { } } - void dumpActiveDurationSummary(PrintWriter pw, final SourceState src, long totalTime, + static void dumpActiveDurationSummary(PrintWriter pw, final SourceState src, long totalTime, long now, boolean dumpAll) { long duration = dumpTime(null, null, src, totalTime, now, false, false); final boolean isRunning = duration < 0; @@ -846,8 +1019,8 @@ public final class AssociationState { pw.println(); } - long dumpTime(PrintWriter pw, String prefix, final SourceState src, long overallTime, long now, - boolean dumpDetails, boolean dumpAll) { + static long dumpTime(PrintWriter pw, String prefix, final SourceState src, long overallTime, + long now, boolean dumpDetails, boolean dumpAll) { long totalTime = 0; boolean isRunning = false; for (int iprocstate = 0; iprocstate < ProcessStats.STATE_COUNT; iprocstate++) { diff --git a/core/java/com/android/internal/app/procstats/DumpUtils.java b/core/java/com/android/internal/app/procstats/DumpUtils.java index b476a17fa9b1..2785c21baf95 100644 --- a/core/java/com/android/internal/app/procstats/DumpUtils.java +++ b/core/java/com/android/internal/app/procstats/DumpUtils.java @@ -27,10 +27,12 @@ import static com.android.internal.app.procstats.ProcessStats.ADJ_SCREEN_MOD; import static com.android.internal.app.procstats.ProcessStats.ADJ_SCREEN_OFF; import static com.android.internal.app.procstats.ProcessStats.ADJ_SCREEN_ON; import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP; +import static com.android.internal.app.procstats.ProcessStats.STATE_BOUND_TOP_OR_FGS; import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY; import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT; import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY; import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT; +import static com.android.internal.app.procstats.ProcessStats.STATE_FGS; import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT; import static com.android.internal.app.procstats.ProcessStats.STATE_HOME; import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND; @@ -70,6 +72,8 @@ public final class DumpUtils { STATE_NAMES = new String[STATE_COUNT]; STATE_NAMES[STATE_PERSISTENT] = "Persist"; STATE_NAMES[STATE_TOP] = "Top"; + STATE_NAMES[STATE_BOUND_TOP_OR_FGS] = "BTopFgs"; + STATE_NAMES[STATE_FGS] = "Fgs"; STATE_NAMES[STATE_IMPORTANT_FOREGROUND] = "ImpFg"; STATE_NAMES[STATE_IMPORTANT_BACKGROUND] = "ImpBg"; STATE_NAMES[STATE_BACKUP] = "Backup"; @@ -86,6 +90,9 @@ public final class DumpUtils { STATE_LABELS = new String[STATE_COUNT]; STATE_LABELS[STATE_PERSISTENT] = "Persistent"; STATE_LABELS[STATE_TOP] = " Top"; + STATE_LABELS[STATE_BOUND_TOP_OR_FGS] = "Bnd TopFgs"; + STATE_LABELS[STATE_FGS] = " Fgs"; + STATE_LABELS[STATE_IMPORTANT_FOREGROUND] = " Imp Fg"; STATE_LABELS[STATE_IMPORTANT_FOREGROUND] = " Imp Fg"; STATE_LABELS[STATE_IMPORTANT_BACKGROUND] = " Imp Bg"; STATE_LABELS[STATE_BACKUP] = " Backup"; @@ -104,6 +111,8 @@ public final class DumpUtils { STATE_NAMES_CSV = new String[STATE_COUNT]; STATE_NAMES_CSV[STATE_PERSISTENT] = "pers"; STATE_NAMES_CSV[STATE_TOP] = "top"; + STATE_NAMES_CSV[STATE_BOUND_TOP_OR_FGS] = "btopfgs"; + STATE_NAMES_CSV[STATE_FGS] = "fgs"; STATE_NAMES_CSV[STATE_IMPORTANT_FOREGROUND] = "impfg"; STATE_NAMES_CSV[STATE_IMPORTANT_BACKGROUND] = "impbg"; STATE_NAMES_CSV[STATE_BACKUP] = "backup"; @@ -120,6 +129,8 @@ public final class DumpUtils { STATE_TAGS = new String[STATE_COUNT]; STATE_TAGS[STATE_PERSISTENT] = "p"; STATE_TAGS[STATE_TOP] = "t"; + STATE_TAGS[STATE_BOUND_TOP_OR_FGS] = "d"; + STATE_TAGS[STATE_FGS] = "g"; STATE_TAGS[STATE_IMPORTANT_FOREGROUND] = "f"; STATE_TAGS[STATE_IMPORTANT_BACKGROUND] = "b"; STATE_TAGS[STATE_BACKUP] = "u"; @@ -136,6 +147,9 @@ public final class DumpUtils { STATE_PROTO_ENUMS = new int[STATE_COUNT]; STATE_PROTO_ENUMS[STATE_PERSISTENT] = ProcessStatsEnums.PROCESS_STATE_PERSISTENT; STATE_PROTO_ENUMS[STATE_TOP] = ProcessStatsEnums.PROCESS_STATE_TOP; + STATE_PROTO_ENUMS[STATE_BOUND_TOP_OR_FGS] = + ProcessStatsEnums.PROCESS_STATE_BOUND_TOP_OR_FGS; + STATE_PROTO_ENUMS[STATE_FGS] = ProcessStatsEnums.PROCESS_STATE_FGS; STATE_PROTO_ENUMS[STATE_IMPORTANT_FOREGROUND] = ProcessStatsEnums.PROCESS_STATE_IMPORTANT_FOREGROUND; STATE_PROTO_ENUMS[STATE_IMPORTANT_BACKGROUND] = @@ -160,6 +174,10 @@ public final class DumpUtils { ProcessStatsEnums.AGGREGATED_PROCESS_STATE_PERSISTENT; PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_TOP] = ProcessStatsEnums.AGGREGATED_PROCESS_STATE_TOP; + PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_BOUND_TOP_OR_FGS] = + ProcessStatsEnums.AGGREGATED_PROCESS_STATE_BOUND_TOP_OR_FGS; + PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_FGS] = + ProcessStatsEnums.AGGREGATED_PROCESS_STATE_FGS; PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_IMPORTANT_FOREGROUND] = ProcessStatsEnums.AGGREGATED_PROCESS_STATE_IMPORTANT_FOREGROUND; PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_IMPORTANT_BACKGROUND] = diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java index ab58fc0eeafc..4bced27cafb4 100644 --- a/core/java/com/android/internal/app/procstats/ProcessState.java +++ b/core/java/com/android/internal/app/procstats/ProcessState.java @@ -28,10 +28,12 @@ import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE; import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM; import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM; import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP; +import static com.android.internal.app.procstats.ProcessStats.STATE_BOUND_TOP_OR_FGS; import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY; import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT; import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY; import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT; +import static com.android.internal.app.procstats.ProcessStats.STATE_FGS; import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT; import static com.android.internal.app.procstats.ProcessStats.STATE_HOME; import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND; @@ -63,6 +65,8 @@ import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoUtils; import com.android.internal.app.ProcessMap; +import com.android.internal.app.procstats.AssociationState.SourceKey; +import com.android.internal.app.procstats.AssociationState.SourceState; import com.android.internal.app.procstats.ProcessStats.PackageState; import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder; import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection; @@ -80,9 +84,9 @@ public final class ProcessState { STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI STATE_TOP, // ActivityManager.PROCESS_STATE_TOP - STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_TOP - STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE - STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE + STATE_BOUND_TOP_OR_FGS, // ActivityManager.PROCESS_STATE_BOUND_TOP + STATE_FGS, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE + STATE_BOUND_TOP_OR_FGS, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND @@ -163,6 +167,11 @@ public final class ProcessState { private long mTmpTotalTime; /** + * The combined source states which has or had an association with this process. + */ + ArrayMap<SourceKey, SourceState> mCommonSources; + + /** * Create a new top-level process state, for the initial case where there is only * a single package running in a process. The initial state is not running. */ @@ -267,6 +276,21 @@ public final class ProcessState { addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss, other.mAvgCachedKillPss, other.mMaxCachedKillPss); } + if (other.mCommonSources != null) { + if (mCommonSources == null) { + mCommonSources = new ArrayMap<>(); + } + int size = other.mCommonSources.size(); + for (int i = 0; i < size; i++) { + final SourceKey key = other.mCommonSources.keyAt(i); + SourceState state = mCommonSources.get(key); + if (state == null) { + state = new SourceState(mStats, null, this, key); + mCommonSources.put(key, state); + } + state.add(other.mCommonSources.valueAt(i)); + } + } } public void resetSafely(long now) { @@ -278,6 +302,17 @@ public final class ProcessState { mNumExcessiveCpu = 0; mNumCachedKill = 0; mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0; + // Reset the combine source state. + if (mCommonSources != null) { + for (int ip = mCommonSources.size() - 1; ip >= 0; ip--) { + final SourceState state = mCommonSources.valueAt(ip); + if (state.isInUse()) { + state.resetSafely(now); + } else { + mCommonSources.removeAt(ip); + } + } + } } public void makeDead() { @@ -308,9 +343,18 @@ public final class ProcessState { out.writeLong(mAvgCachedKillPss); out.writeLong(mMaxCachedKillPss); } + // The combined source state of all associations. + final int numOfSources = mCommonSources != null ? mCommonSources.size() : 0; + out.writeInt(numOfSources); + for (int i = 0; i < numOfSources; i++) { + final SourceKey key = mCommonSources.keyAt(i); + final SourceState src = mCommonSources.valueAt(i); + key.writeToParcel(mStats, out); + src.writeToParcel(out, 0); + } } - public boolean readFromParcel(Parcel in, boolean fully) { + boolean readFromParcel(Parcel in, int version, boolean fully) { boolean multiPackage = in.readInt() != 0; if (fully) { mMultiPackage = multiPackage; @@ -337,6 +381,19 @@ public final class ProcessState { } else { mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0; } + + // The combined source state of all associations. + final int numOfSources = in.readInt(); + if (numOfSources > 0) { + mCommonSources = new ArrayMap<>(numOfSources); + for (int i = 0; i < numOfSources; i++) { + final SourceKey key = new SourceKey(mStats, in, version); + final SourceState src = new SourceState(mStats, null, this, key); + src.readFromParcel(in); + mCommonSources.put(key, src); + } + } + return true; } @@ -433,6 +490,12 @@ public final class ProcessState { mTotalRunningStartTime = now; } mStartTime = now; + if (mCommonSources != null) { + for (int ip = mCommonSources.size() - 1; ip >= 0; ip--) { + final SourceState src = mCommonSources.valueAt(ip); + src.commitStateTime(now); + } + } } public void incActiveServices(String serviceName) { @@ -722,6 +785,18 @@ public final class ProcessState { return mPssTable.getValueForId((byte)state, PSS_RSS_MAXIMUM); } + SourceState getOrCreateSourceState(SourceKey key) { + if (mCommonSources == null) { + mCommonSources = new ArrayMap<>(); + } + SourceState state = mCommonSources.get(key); + if (state == null) { + state = new SourceState(mStats, null, this, key); + mCommonSources.put(key, state); + } + return state; + } + /** * Sums up the PSS data and adds it to 'data'. * @@ -846,6 +921,12 @@ public final class ProcessState { screenStates, memStates, new int[] { STATE_PERSISTENT }, now, totalTime, true); dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_TOP], screenStates, memStates, new int[] {STATE_TOP}, now, totalTime, true); + dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BOUND_TOP_OR_FGS], + screenStates, memStates, new int[] { STATE_BOUND_TOP_OR_FGS}, now, totalTime, + true); + dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_FGS], + screenStates, memStates, new int[] { STATE_FGS}, now, totalTime, + true); dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_IMPORTANT_FOREGROUND], screenStates, memStates, new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true); @@ -1038,7 +1119,8 @@ public final class ProcessState { } } - public void dumpInternalLocked(PrintWriter pw, String prefix, boolean dumpAll) { + void dumpInternalLocked(PrintWriter pw, String prefix, String reqPackage, + long totalTime, long now, boolean dumpAll) { if (dumpAll) { pw.print(prefix); pw.print("myID="); pw.print(Integer.toHexString(System.identityHashCode(this))); @@ -1053,6 +1135,13 @@ public final class ProcessState { pw.print("/"); pw.print(mCommonProcess.mUid); pw.print(" pkg="); pw.println(mCommonProcess.mPackage); } + if (mCommonSources != null) { + pw.print(prefix); pw.println("Aggregated Association Sources:"); + AssociationState.dumpSources( + pw, prefix + " ", prefix + " ", prefix + " ", + AssociationState.createSortedAssociations(now, totalTime, mCommonSources), + now, totalTime, reqPackage, true, dumpAll); + } } if (mActive) { pw.print(prefix); pw.print("mActive="); pw.println(mActive); @@ -1559,7 +1648,7 @@ public final class ProcessState { } mStats.dumpFilteredAssociationStatesProtoForProc(proto, ProcessStatsProto.ASSOCS, - now, this, procToPkgMap, uidToPkgMap); + now, this, uidToPkgMap); proto.end(token); } } diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java index 11e55b852516..fd16662f1b68 100644 --- a/core/java/com/android/internal/app/procstats/ProcessStats.java +++ b/core/java/com/android/internal/app/procstats/ProcessStats.java @@ -29,7 +29,6 @@ import android.service.procstats.ProcessStatsAssociationProto; import android.service.procstats.ProcessStatsAvailablePagesProto; import android.service.procstats.ProcessStatsPackageProto; import android.service.procstats.ProcessStatsSectionProto; -import android.text.TextUtils; import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArraySet; @@ -79,18 +78,20 @@ public final class ProcessStats implements Parcelable { public static final int STATE_NOTHING = -1; public static final int STATE_PERSISTENT = 0; public static final int STATE_TOP = 1; - public static final int STATE_IMPORTANT_FOREGROUND = 2; - public static final int STATE_IMPORTANT_BACKGROUND = 3; - public static final int STATE_BACKUP = 4; - public static final int STATE_SERVICE = 5; - public static final int STATE_SERVICE_RESTARTING = 6; - public static final int STATE_RECEIVER = 7; - public static final int STATE_HEAVY_WEIGHT = 8; - public static final int STATE_HOME = 9; - public static final int STATE_LAST_ACTIVITY = 10; - public static final int STATE_CACHED_ACTIVITY = 11; - public static final int STATE_CACHED_ACTIVITY_CLIENT = 12; - public static final int STATE_CACHED_EMPTY = 13; + public static final int STATE_BOUND_TOP_OR_FGS = 2; + public static final int STATE_FGS = 3; + public static final int STATE_IMPORTANT_FOREGROUND = 4; + public static final int STATE_IMPORTANT_BACKGROUND = 5; + public static final int STATE_BACKUP = 6; + public static final int STATE_SERVICE = 7; + public static final int STATE_SERVICE_RESTARTING = 8; + public static final int STATE_RECEIVER = 9; + public static final int STATE_HEAVY_WEIGHT = 10; + public static final int STATE_HOME = 11; + public static final int STATE_LAST_ACTIVITY = 12; + public static final int STATE_CACHED_ACTIVITY = 13; + public static final int STATE_CACHED_ACTIVITY_CLIENT = 14; + public static final int STATE_CACHED_EMPTY = 15; public static final int STATE_COUNT = STATE_CACHED_EMPTY+1; public static final int PSS_SAMPLE_COUNT = 0; @@ -150,8 +151,8 @@ public final class ProcessStats implements Parcelable { public static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON }; public static final int[] NON_CACHED_PROC_STATES = new int[] { - STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND, - STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, + STATE_PERSISTENT, STATE_TOP, STATE_BOUND_TOP_OR_FGS, STATE_FGS, + STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER, STATE_HEAVY_WEIGHT }; @@ -161,7 +162,8 @@ public final class ProcessStats implements Parcelable { }; public static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT, - STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, + STATE_TOP, STATE_BOUND_TOP_OR_FGS, STATE_FGS, STATE_IMPORTANT_FOREGROUND, + STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER, STATE_HEAVY_WEIGHT, STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY @@ -187,7 +189,7 @@ public final class ProcessStats implements Parcelable { {"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"}; // Current version of the parcel format. - private static final int PARCEL_VERSION = 38; + private static final int PARCEL_VERSION = 40; // In-memory Parcel magic number, used to detect attempts to unmarshall bad data private static final int MAGIC = 0x50535454; @@ -1113,12 +1115,12 @@ public final class ProcessStats implements Parcelable { final long vers = in.readLong(); ProcessState proc = hadData ? mProcesses.get(procName, uid) : null; if (proc != null) { - if (!proc.readFromParcel(in, false)) { + if (!proc.readFromParcel(in, version, false)) { return; } } else { proc = new ProcessState(this, pkgName, uid, vers, procName); - if (!proc.readFromParcel(in, true)) { + if (!proc.readFromParcel(in, version, true)) { return; } } @@ -1198,13 +1200,13 @@ public final class ProcessStats implements Parcelable { // they will find and use it from the global procs. ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null; if (proc != null) { - if (!proc.readFromParcel(in, false)) { + if (!proc.readFromParcel(in, version, false)) { return; } } else { proc = new ProcessState(commonProc, pkgName, uid, vers, procName, 0); - if (!proc.readFromParcel(in, true)) { + if (!proc.readFromParcel(in, version, true)) { return; } } @@ -1439,16 +1441,15 @@ public final class ProcessStats implements Parcelable { final int NUM = mTrackingAssociations.size(); for (int i = NUM - 1; i >= 0; i--) { final AssociationState.SourceState act = mTrackingAssociations.get(i); - if (act.mProcStateSeq != curSeq || act.mProcState >= ProcessStats.STATE_HOME) { - // If this association did not get touched the last time we computed - // process states, or its state ended up down in cached, then we no - // longer have a reason to track it at all. - act.stopActive(now); - act.mInTrackingList = false; - act.mProcState = ProcessStats.STATE_NOTHING; + if (act.stopActiveIfNecessary(curSeq, now)) { mTrackingAssociations.remove(i); } else { - final ProcessState proc = act.getAssociationState().getProcess(); + final AssociationState asc = act.getAssociationState(); + if (asc == null) { + Slog.wtf(TAG, act.toString() + " shouldn't be in the tracking list."); + continue; + } + final ProcessState proc = asc.getProcess(); if (proc != null) { final int procState = proc.getCombinedState() % STATE_COUNT; if (act.mProcState == procState) { @@ -1476,7 +1477,7 @@ public final class ProcessStats implements Parcelable { } else { // Don't need rate limiting on it. Slog.wtf(TAG, "Tracking association without process: " + act - + " in " + act.getAssociationState()); + + " in " + asc); } } } @@ -1640,7 +1641,8 @@ public final class ProcessStats implements Parcelable { ALL_PROC_STATES, now); proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now); - proc.dumpInternalLocked(pw, " ", dumpAll); + proc.dumpInternalLocked(pw, " ", reqPackage, + totalTime, now, dumpAll); } } else { ArrayList<ProcessState> procs = new ArrayList<ProcessState>(); @@ -1696,7 +1698,8 @@ public final class ProcessStats implements Parcelable { } final AssociationDumpContainer cont = new AssociationDumpContainer(asc); - cont.mSources = asc.createSortedAssociations(now, totalTime); + cont.mSources = AssociationState + .createSortedAssociations(now, totalTime, asc.mSources); cont.mTotalTime = asc.getTotalDuration(now); cont.mActiveTime = asc.getActiveDuration(now); associations.add(cont); @@ -1777,7 +1780,7 @@ public final class ProcessStats implements Parcelable { proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now); proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now); - proc.dumpInternalLocked(pw, " ", dumpAll); + proc.dumpInternalLocked(pw, " ", reqPackage, totalTime, now, dumpAll); } } pw.print(" Total procs: "); pw.print(numShownProcs); @@ -1792,6 +1795,10 @@ public final class ProcessStats implements Parcelable { for (int i = 0; i < mTrackingAssociations.size(); i++) { final AssociationState.SourceState src = mTrackingAssociations.get(i); final AssociationState asc = src.getAssociationState(); + if (asc == null) { + Slog.wtf(TAG, src.toString() + " shouldn't be in the tracking list."); + continue; + } pw.print(" #"); pw.print(i); pw.print(": "); @@ -2353,85 +2360,47 @@ public final class ProcessStats implements Parcelable { * @param fieldId The proto output field ID * @param now The timestamp when the dump was initiated. * @param procState The target process where its association states should be dumped. - * @param proc2Pkg The map between process to packages running within it. * @param uidToPkgMap The map between UID to packages with this UID */ public void dumpFilteredAssociationStatesProtoForProc(ProtoOutputStream proto, long fieldId, long now, ProcessState procState, - final ProcessMap<ArraySet<PackageState>> proc2Pkg, final SparseArray<ArraySet<String>> uidToPkgMap) { if (procState.isMultiPackage() && procState.getCommonProcess() != procState) { // It's a per-package process state, don't bother to write into statsd return; } - ArrayMap<SourceKey, long[]> assocVals = new ArrayMap<>(); - final String procName = procState.getName(); - final int procUid = procState.getUid(); - final long procVersion = procState.getVersion(); - final ArraySet<PackageState> packages = proc2Pkg.get(procName, procUid); - if (packages == null || packages.isEmpty()) { - // Shouldn't happen - return; - } - for (int i = packages.size() - 1; i >= 0; i--) { - final PackageState pkgState = packages.valueAt(i); - final ArrayMap<String, AssociationState> associations = pkgState.mAssociations; - for (int j = associations.size() - 1; j >= 0; j--) { - final AssociationState assoc = associations.valueAt(j); - // Make sure this association is really about this process - if (!TextUtils.equals(assoc.getProcessName(), procName)) { - continue; - } - final ArrayMap<SourceKey, SourceState> sources = assoc.mSources; - for (int k = sources.size() - 1; k >= 0; k--) { - final SourceKey key = sources.keyAt(k); - final SourceState state = sources.valueAt(k); - long[] vals = assocVals.get(key); - if (vals == null) { - vals = new long[2]; - assocVals.put(key, vals); - } - vals[0] += state.mDuration; - vals[1] += state.mCount; - if (state.mNesting > 0) { - vals[0] += now - state.mStartUptime; - } - } - } - } - final IProcessStats procStatsService = IProcessStats.Stub.asInterface( - ServiceManager.getService(SERVICE_NAME)); - if (procStatsService != null) { - try { - final long minimum = procStatsService.getMinAssociationDumpDuration(); - if (minimum > 0) { - // Now filter out unnecessary ones. - for (int i = assocVals.size() - 1; i >= 0; i--) { - final long[] vals = assocVals.valueAt(i); - if (vals[0] < minimum) { - assocVals.removeAt(i); + final ArrayMap<SourceKey, SourceState> sources = procState.mCommonSources; + if (sources != null && !sources.isEmpty()) { + final IProcessStats procStatsService = IProcessStats.Stub.asInterface( + ServiceManager.getService(SERVICE_NAME)); + if (procStatsService != null) { + try { + final long minimum = procStatsService.getMinAssociationDumpDuration(); + for (int i = sources.size() - 1; i >= 0; i--) { + final SourceState src = sources.valueAt(i); + long duration = src.mDuration; + if (src.mNesting > 0) { + duration += now - src.mStartUptime; + } + if (duration < minimum) { + continue; } + final SourceKey key = sources.keyAt(i); + final long token = proto.start(fieldId); + final int idx = uidToPkgMap.indexOfKey(key.mUid); + ProcessState.writeCompressedProcessName(proto, + ProcessStatsAssociationProto.ASSOC_PROCESS_NAME, + key.mProcess, key.mPackage, + idx >= 0 && uidToPkgMap.valueAt(idx).size() > 1); + proto.write(ProcessStatsAssociationProto.ASSOC_UID, key.mUid); + proto.write(ProcessStatsAssociationProto.TOTAL_COUNT, src.mCount); + proto.write(ProcessStatsAssociationProto.TOTAL_DURATION_SECS, + (int) (duration / 1000)); + proto.end(token); } + } catch (RemoteException e) { + // ignore. } - } catch (RemoteException e) { - // ignore. - } - } - if (!assocVals.isEmpty()) { - for (int i = assocVals.size() - 1; i >= 0; i--) { - final SourceKey key = assocVals.keyAt(i); - final long[] vals = assocVals.valueAt(i); - final long token = proto.start(fieldId); - final int idx = uidToPkgMap.indexOfKey(key.mUid); - ProcessState.writeCompressedProcessName(proto, - ProcessStatsAssociationProto.ASSOC_PROCESS_NAME, - key.mProcess, key.mPackage, - idx >= 0 && uidToPkgMap.valueAt(idx).size() > 1); - proto.write(ProcessStatsAssociationProto.ASSOC_UID, key.mUid); - proto.write(ProcessStatsAssociationProto.TOTAL_COUNT, (int) vals[1]); - proto.write(ProcessStatsAssociationProto.TOTAL_DURATION_SECS, - (int) (vals[0] / 1000)); - proto.end(token); } } } diff --git a/core/java/com/android/internal/graphics/OWNERS b/core/java/com/android/internal/graphics/OWNERS new file mode 100644 index 000000000000..5851cbbdf33c --- /dev/null +++ b/core/java/com/android/internal/graphics/OWNERS @@ -0,0 +1 @@ +include /graphics/java/android/graphics/OWNERS
\ No newline at end of file diff --git a/core/java/com/android/internal/graphics/palette/LABCentroid.java b/core/java/com/android/internal/graphics/palette/LABCentroid.java index 98d5d2684857..408cf1fe9193 100644 --- a/core/java/com/android/internal/graphics/palette/LABCentroid.java +++ b/core/java/com/android/internal/graphics/palette/LABCentroid.java @@ -62,6 +62,6 @@ public class LABCentroid implements CentroidProvider { double dL = a[0] - b[0]; double dA = a[1] - b[1]; double dB = a[2] - b[2]; - return (float) (Math.pow(dL, 2) + Math.pow(dA, 2) + Math.pow(dB, 2)); + return (float) (dL * dL + dA * dA + dB * dB); } } diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl index fcb5d3bb1bf0..11df5a89d8c0 100644 --- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl +++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl @@ -39,11 +39,10 @@ oneway interface IInputMethodPrivilegedOperations { in IVoidResultCallback resultCallback); void hideMySoftInput(int flags, in IVoidResultCallback resultCallback); void showMySoftInput(int flags, in IVoidResultCallback resultCallback); - void updateStatusIcon(String packageName, int iconId, in IVoidResultCallback resultCallback); + void updateStatusIconAsync(String packageName, int iconId); void switchToPreviousInputMethod(in IBooleanResultCallback resultCallback); void switchToNextInputMethod(boolean onlyCurrentIme, in IBooleanResultCallback resultCallback); void shouldOfferSwitchingToNextInputMethod(in IBooleanResultCallback resultCallback); - void notifyUserAction(in IVoidResultCallback resultCallback); - void applyImeVisibility(IBinder showOrHideInputToken, boolean setVisible, - in IVoidResultCallback resultCallback); + void notifyUserActionAsync(); + void applyImeVisibilityAsync(IBinder showOrHideInputToken, boolean setVisible); } diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java index 93374ba0cf46..a00b993749a5 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java +++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java @@ -230,6 +230,12 @@ public final class InputMethodDebug { return "HIDE_REMOVE_CLIENT"; case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY: return "SHOW_RESTORE_IME_VISIBILITY"; + case SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT: + return "SHOW_TOGGLE_SOFT_INPUT"; + case SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT: + return "HIDE_TOGGLE_SOFT_INPUT"; + case SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API: + return "SHOW_SOFT_INPUT_BY_INSETS_API"; default: return "Unknown=" + reason; } diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java index 1691e13fa567..ed1fe1a6229e 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java +++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java @@ -187,22 +187,19 @@ public final class InputMethodPrivilegedOperations { } /** - * Calls {@link IInputMethodPrivilegedOperations#updateStatusIcon(String, int, - * IVoidResultCallback)}. + * Calls {@link IInputMethodPrivilegedOperations#updateStatusIconAsync(String, int)}. * * @param packageName package name from which the status icon should be loaded * @param iconResId resource ID of the icon to be loaded */ @AnyThread - public void updateStatusIcon(String packageName, @DrawableRes int iconResId) { + public void updateStatusIconAsync(String packageName, @DrawableRes int iconResId) { final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull(); if (ops == null) { return; } try { - final Completable.Void value = Completable.createVoid(); - ops.updateStatusIcon(packageName, iconResId, ResultCallbacks.of(value)); - Completable.getResult(value); + ops.updateStatusIconAsync(packageName, iconResId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -362,26 +359,23 @@ public final class InputMethodPrivilegedOperations { } /** - * Calls {@link IInputMethodPrivilegedOperations#notifyUserAction(IVoidResultCallback)} + * Calls {@link IInputMethodPrivilegedOperations#notifyUserActionAsync()} */ @AnyThread - public void notifyUserAction() { + public void notifyUserActionAsync() { final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull(); if (ops == null) { return; } try { - final Completable.Void value = Completable.createVoid(); - ops.notifyUserAction(ResultCallbacks.of(value)); - Completable.getResult(value); + ops.notifyUserActionAsync(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Calls {@link IInputMethodPrivilegedOperations#applyImeVisibility(IBinder, boolean, - * IVoidResultCallback)}. + * Calls {@link IInputMethodPrivilegedOperations#applyImeVisibilityAsync(IBinder, boolean)}. * * @param showOrHideInputToken placeholder token that maps to window requesting * {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} or @@ -390,15 +384,13 @@ public final class InputMethodPrivilegedOperations { * @param setVisible {@code true} to set IME visible, else hidden. */ @AnyThread - public void applyImeVisibility(IBinder showOrHideInputToken, boolean setVisible) { + public void applyImeVisibilityAsync(IBinder showOrHideInputToken, boolean setVisible) { final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull(); if (ops == null) { return; } try { - final Completable.Void value = Completable.createVoid(); - ops.applyImeVisibility(showOrHideInputToken, setVisible, ResultCallbacks.of(value)); - Completable.getResult(value); + ops.applyImeVisibilityAsync(showOrHideInputToken, setVisible); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java index f1cdf2b38c4c..e3713a3b8971 100644 --- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java +++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java @@ -50,7 +50,10 @@ import java.lang.annotation.Retention; SoftInputShowHideReason.HIDE_BUBBLES, SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR, SoftInputShowHideReason.HIDE_REMOVE_CLIENT, - SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY}) + SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY, + SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT, + SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT, + SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API}) public @interface SoftInputShowHideReason { /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */ int SHOW_SOFT_INPUT = 0; @@ -174,4 +177,22 @@ public @interface SoftInputShowHideReason { * {@link com.android.server.wm.WindowManagerInternal#shouldRestoreImeVisibility}. */ int SHOW_RESTORE_IME_VISIBILITY = 22; + + /** + * Show soft input by + * {@link android.view.inputmethod.InputMethodManager#toggleSoftInput(int, int)}; + */ + int SHOW_TOGGLE_SOFT_INPUT = 23; + + /** + * Hide soft input by + * {@link android.view.inputmethod.InputMethodManager#toggleSoftInput(int, int)}; + */ + int HIDE_TOGGLE_SOFT_INPUT = 24; + + /** + * Show soft input by + * {@link android.view.InsetsController#show(int)}; + */ + int SHOW_SOFT_INPUT_BY_INSETS_API = 25; } diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java index aa416c568dbc..73d962effc00 100644 --- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java +++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java @@ -53,7 +53,7 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { builder.getOrCreateSystemBatteryConsumerBuilder( SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, powerMah, powerModel) - .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN, durationMs); + .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN, durationMs); } /** diff --git a/core/java/com/android/internal/os/AudioPowerCalculator.java b/core/java/com/android/internal/os/AudioPowerCalculator.java index 79b331da9c8a..9da8191f3747 100644 --- a/core/java/com/android/internal/os/AudioPowerCalculator.java +++ b/core/java/com/android/internal/os/AudioPowerCalculator.java @@ -42,7 +42,7 @@ public class AudioPowerCalculator extends PowerCalculator { final long durationMs = mPowerEstimator.calculateDuration(u.getAudioTurnedOnTimer(), rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); final double powerMah = mPowerEstimator.calculatePower(durationMs); - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO, durationMs) + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO, powerMah); } } diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java index 9ad7c15b9a9c..babcea14d0ea 100644 --- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java +++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java @@ -124,16 +124,11 @@ public class BatteryUsageStatsProvider { final long realtimeUs = elapsedRealtime() * 1000; final long uptimeUs = uptimeMillis() * 1000; - final String[] customPowerComponentNames = mStats.getCustomEnergyConsumerNames(); - - // TODO(b/174186358): read extra time component number from configuration - final int customTimeComponentCount = 0; - final boolean includePowerModels = (query.getFlags() & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0; final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder( - customPowerComponentNames, customTimeComponentCount, includePowerModels); + mStats.getCustomEnergyConsumerNames(), includePowerModels); batteryUsageStatsBuilder.setStatsStartTimestamp(mStats.getStartClockTime()); SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats(); diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 30a35367d6f5..1004e17e91e6 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -16,18 +16,25 @@ package com.android.internal.os; +import static com.android.internal.os.BinderLatencyProto.Dims.SYSTEM_SERVER; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; +import android.provider.Settings; import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IntArray; +import android.util.KeyValueListParser; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -57,7 +64,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false; public static final boolean DEFAULT_TRACK_DIRECT_CALLING_UID = true; public static final boolean DEFAULT_IGNORE_BATTERY_STATUS = false; - public static final boolean DEFAULT_COLLECT_LATENCY_DATA = false; + public static final boolean DEFAULT_COLLECT_LATENCY_DATA = true; public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 1500; private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; @@ -157,15 +164,20 @@ public class BinderCallsStats implements BinderInternal.Observer { return new Handler(Looper.getMainLooper()); } - public BinderLatencyObserver getLatencyObserver() { - return new BinderLatencyObserver(new BinderLatencyObserver.Injector()); + /** Create a latency observer for the specified process. */ + public BinderLatencyObserver getLatencyObserver(int processSource) { + return new BinderLatencyObserver(new BinderLatencyObserver.Injector(), processSource); } } public BinderCallsStats(Injector injector) { + this(injector, SYSTEM_SERVER); + } + + public BinderCallsStats(Injector injector, int processSource) { this.mRandom = injector.getRandomGenerator(); this.mCallStatsObserverHandler = injector.getHandler(); - this.mLatencyObserver = injector.getLatencyObserver(); + this.mLatencyObserver = injector.getLatencyObserver(processSource); } public void setDeviceState(@NonNull CachedDeviceState.Readonly deviceState) { @@ -1074,4 +1086,120 @@ public class BinderCallsStats implements BinderInternal.Observer { ? result : Integer.compare(a.transactionCode, b.transactionCode); } + + + /** + * Settings observer for other processes (not system_server). + * + * We do not want to collect cpu data from other processes so only latency collection should be + * possible to enable. + */ + public static class SettingsObserver extends ContentObserver { + // Settings for BinderCallsStats. + public static final String SETTINGS_ENABLED_KEY = "enabled"; + public static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking"; + public static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data"; + public static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; + public static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state"; + public static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid"; + public static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count"; + public static final String SETTINGS_IGNORE_BATTERY_STATUS_KEY = "ignore_battery_status"; + // Settings for BinderLatencyObserver. + public static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_Latency_data"; + public static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY = + "latency_observer_sampling_interval"; + public static final String SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY = + "latency_observer_push_interval_minutes"; + public static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY = + "latency_histogram_bucket_count"; + public static final String SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY = + "latency_histogram_first_bucket_size"; + public static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY = + "latency_histogram_bucket_scale_factor"; + + private boolean mEnabled; + private final Uri mUri = Settings.Global.getUriFor(Settings.Global.BINDER_CALLS_STATS); + private final Context mContext; + private final KeyValueListParser mParser = new KeyValueListParser(','); + private final BinderCallsStats mBinderCallsStats; + private final int mProcessSource; + + public SettingsObserver(Context context, BinderCallsStats binderCallsStats, + int processSource, int userHandle) { + super(BackgroundThread.getHandler()); + mContext = context; + context.getContentResolver().registerContentObserver(mUri, false, this, + userHandle); + mBinderCallsStats = binderCallsStats; + mProcessSource = processSource; + // Always kick once to ensure that we match current state + onChange(); + } + + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + if (mUri.equals(uri)) { + onChange(); + } + } + + void onChange() { + try { + mParser.setString(Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.BINDER_CALLS_STATS)); + } catch (IllegalArgumentException e) { + Slog.e(TAG, "Bad binder call stats settings", e); + } + + // Cpu data collection should always be disabled for other processes. + mBinderCallsStats.setDetailedTracking(false); + mBinderCallsStats.setTrackScreenInteractive(false); + mBinderCallsStats.setTrackDirectCallerUid(false); + + mBinderCallsStats.setIgnoreBatteryStatus( + mParser.getBoolean(SETTINGS_IGNORE_BATTERY_STATUS_KEY, + BinderCallsStats.DEFAULT_IGNORE_BATTERY_STATUS)); + mBinderCallsStats.setCollectLatencyData( + mParser.getBoolean(SETTINGS_COLLECT_LATENCY_DATA_KEY, + BinderCallsStats.DEFAULT_COLLECT_LATENCY_DATA)); + + // Binder latency observer settings. + configureLatencyObserver(mParser, mBinderCallsStats.getLatencyObserver()); + + final boolean enabled = + mParser.getBoolean(SETTINGS_ENABLED_KEY, BinderCallsStats.ENABLED_DEFAULT); + if (mEnabled != enabled) { + if (enabled) { + Binder.setObserver(mBinderCallsStats); + } else { + Binder.setObserver(null); + } + mEnabled = enabled; + mBinderCallsStats.reset(); + mBinderCallsStats.setAddDebugEntries(enabled); + mBinderCallsStats.getLatencyObserver().reset(); + } + } + + /** Configures the binder latency observer related settings. */ + public static void configureLatencyObserver( + KeyValueListParser mParser, BinderLatencyObserver binderLatencyObserver) { + binderLatencyObserver.setSamplingInterval(mParser.getInt( + SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY, + BinderLatencyObserver.PERIODIC_SAMPLING_INTERVAL_DEFAULT)); + binderLatencyObserver.setHistogramBucketsParams( + mParser.getInt( + SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY, + BinderLatencyObserver.BUCKET_COUNT_DEFAULT), + mParser.getInt( + SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY, + BinderLatencyObserver.FIRST_BUCKET_SIZE_DEFAULT), + mParser.getFloat( + SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY, + BinderLatencyObserver.BUCKET_SCALE_FACTOR_DEFAULT)); + binderLatencyObserver.setPushInterval(mParser.getInt( + SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY, + BinderLatencyObserver.STATSD_PUSH_INTERVAL_MINUTES_DEFAULT)); + } + } } diff --git a/core/java/com/android/internal/os/BinderLatencyObserver.java b/core/java/com/android/internal/os/BinderLatencyObserver.java index 007980150237..5fa96bd9a152 100644 --- a/core/java/com/android/internal/os/BinderLatencyObserver.java +++ b/core/java/com/android/internal/os/BinderLatencyObserver.java @@ -16,8 +16,6 @@ package com.android.internal.os; -import static com.android.internal.os.BinderLatencyProto.Dims.SYSTEM_SERVER; - import android.annotation.Nullable; import android.os.Binder; import android.os.Handler; @@ -68,9 +66,10 @@ public class BinderLatencyObserver { private int mStatsdPushIntervalMinutes = STATSD_PUSH_INTERVAL_MINUTES_DEFAULT; private final Random mRandom; - private BinderLatencyBuckets mLatencyBuckets; - private final Handler mLatencyObserverHandler; + private final int mProcessSource; + + private BinderLatencyBuckets mLatencyBuckets; private Runnable mLatencyObserverRunnable = new Runnable() { @Override @@ -134,7 +133,7 @@ public class BinderLatencyObserver { // Write the dims. long dimsToken = proto.start(ApiStats.DIMS); - proto.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER); + proto.write(Dims.PROCESS_SOURCE, mProcessSource); proto.write(Dims.SERVICE_CLASS_NAME, dims.getBinderClass().getName()); proto.write(Dims.SERVICE_METHOD_NAME, transactionName); proto.end(dimsToken); @@ -180,11 +179,12 @@ public class BinderLatencyObserver { } } - public BinderLatencyObserver(Injector injector) { + public BinderLatencyObserver(Injector injector, int processSource) { mRandom = injector.getRandomGenerator(); mLatencyObserverHandler = injector.getHandler(); mLatencyBuckets = new BinderLatencyBuckets( mBucketCount, mFirstBucketSize, mBucketScaleFactor); + mProcessSource = processSource; noteLatencyDelayed(); } diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java index a418dfff5d8f..2c32e48c9685 100644 --- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java +++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java @@ -88,7 +88,7 @@ public class BluetoothPowerCalculator extends PowerCalculator { + " power=" + formatCharge(systemPowerMah)); } systemBatteryConsumerBuilder - .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH, + .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, systemComponentDurationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, Math.max(systemPowerMah, total.powerMah), powerModel) @@ -105,7 +105,7 @@ public class BluetoothPowerCalculator extends PowerCalculator { final long durationMs = calculateDuration(activityCounter); final double powerMah = calculatePowerMah(powerModel, measuredChargeUC, activityCounter); - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH, durationMs) + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerMah, powerModel); total.durationMs += durationMs; diff --git a/core/java/com/android/internal/os/CameraPowerCalculator.java b/core/java/com/android/internal/os/CameraPowerCalculator.java index 6f8e9271d198..e56e7beddecb 100644 --- a/core/java/com/android/internal/os/CameraPowerCalculator.java +++ b/core/java/com/android/internal/os/CameraPowerCalculator.java @@ -42,7 +42,7 @@ public class CameraPowerCalculator extends PowerCalculator { mPowerEstimator.calculateDuration(u.getCameraTurnedOnTimer(), rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); final double powerMah = mPowerEstimator.calculatePower(durationMs); - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CAMERA, durationMs) + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah); } diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java index 4aafec555182..2a55aa9daf6c 100644 --- a/core/java/com/android/internal/os/CpuPowerCalculator.java +++ b/core/java/com/android/internal/os/CpuPowerCalculator.java @@ -97,9 +97,7 @@ public class CpuPowerCalculator extends PowerCalculator { result); app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, result.powerMah, powerModel) - .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, result.durationMs) - .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, - result.durationFgMs) + .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU, result.durationMs) .setPackageWithHighestDrain(result.packageWithHighestDrain); } diff --git a/core/java/com/android/internal/os/FlashlightPowerCalculator.java b/core/java/com/android/internal/os/FlashlightPowerCalculator.java index 6c29a91f081f..cbe0cde2f5b7 100644 --- a/core/java/com/android/internal/os/FlashlightPowerCalculator.java +++ b/core/java/com/android/internal/os/FlashlightPowerCalculator.java @@ -39,7 +39,7 @@ public class FlashlightPowerCalculator extends PowerCalculator { final long durationMs = mPowerEstimator.calculateDuration(u.getFlashlightTurnedOnTimer(), rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); final double powerMah = mPowerEstimator.calculatePower(durationMs); - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_FLASHLIGHT, durationMs) + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, powerMah); } diff --git a/core/java/com/android/internal/os/GnssPowerCalculator.java b/core/java/com/android/internal/os/GnssPowerCalculator.java index 0e0870de4f5f..7eb4b4a9bb1c 100644 --- a/core/java/com/android/internal/os/GnssPowerCalculator.java +++ b/core/java/com/android/internal/os/GnssPowerCalculator.java @@ -74,7 +74,7 @@ public class GnssPowerCalculator extends PowerCalculator { powerMah = computePower(durationMs, averageGnssPowerMa); } - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS, durationMs) + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_GNSS, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS, powerMah, powerModel); } diff --git a/core/java/com/android/internal/os/IdlePowerCalculator.java b/core/java/com/android/internal/os/IdlePowerCalculator.java index 5cb54bd7fbc9..0c80deb49259 100644 --- a/core/java/com/android/internal/os/IdlePowerCalculator.java +++ b/core/java/com/android/internal/os/IdlePowerCalculator.java @@ -55,7 +55,7 @@ public class IdlePowerCalculator extends PowerCalculator { if (mPowerMah != 0) { builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_IDLE) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE, mPowerMah) - .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_IDLE, mDurationMs); + .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_IDLE, mDurationMs); } } diff --git a/core/java/com/android/internal/os/MemoryPowerCalculator.java b/core/java/com/android/internal/os/MemoryPowerCalculator.java index 9ec40c6f6eed..5d5c1558f716 100644 --- a/core/java/com/android/internal/os/MemoryPowerCalculator.java +++ b/core/java/com/android/internal/os/MemoryPowerCalculator.java @@ -32,7 +32,7 @@ public class MemoryPowerCalculator extends PowerCalculator { final double powerMah = calculatePower(batteryStats, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_MEMORY) - .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MEMORY, durationMs) + .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MEMORY, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY, powerMah); } diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java index d441d4529aca..4db15a44231e 100644 --- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java +++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java @@ -107,7 +107,7 @@ public class MobileRadioPowerCalculator extends PowerCalculator { if (total.remainingPowerMah != 0 || total.totalAppPowerMah != 0) { builder.getOrCreateSystemBatteryConsumerBuilder( SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO) - .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MOBILE_RADIO, + .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, total.durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, total.remainingPowerMah + total.totalAppPowerMah, @@ -128,7 +128,7 @@ public class MobileRadioPowerCalculator extends PowerCalculator { radioActiveDurationMs, consumptionUC); total.totalAppPowerMah += powerMah; - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MOBILE_RADIO, + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, radioActiveDurationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, powerMah, powerModel); diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java index 6f279d99a5c9..2e3bff32cc38 100644 --- a/core/java/com/android/internal/os/PhonePowerCalculator.java +++ b/core/java/com/android/internal/os/PhonePowerCalculator.java @@ -46,7 +46,7 @@ public class PhonePowerCalculator extends PowerCalculator { if (phoneOnPower != 0) { builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_PHONE) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower) - .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_PHONE, phoneOnTimeMs); + .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs); } } diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java index 0743c897a91f..dc0f719c042b 100644 --- a/core/java/com/android/internal/os/ScreenPowerCalculator.java +++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java @@ -81,7 +81,7 @@ public class ScreenPowerCalculator extends PowerCalculator { final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); calculateAppUsingMeasuredEnergy(appPowerAndDuration, app.getBatteryStatsUid(), rawRealtimeUs); - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN, + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN, appPowerAndDuration.durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, appPowerAndDuration.powerMah, powerModel); @@ -96,7 +96,7 @@ public class ScreenPowerCalculator extends PowerCalculator { } builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_SCREEN) - .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN, + .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN, totalPowerAndDuration.durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, Math.max(totalPowerAndDuration.powerMah, totalAppPower), powerModel) @@ -251,7 +251,7 @@ public class ScreenPowerCalculator extends PowerCalculator { final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); final long durationMs = activityTimeArray.get(app.getUid(), 0); final double powerMah = totalScreenPowerMah * durationMs / totalActivityTimeMs; - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN, durationMs) + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, powerMah, BatteryConsumer.POWER_MODEL_POWER_PROFILE); } diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java index 78c4fe2060f1..d18b7b1f69c2 100644 --- a/core/java/com/android/internal/os/SensorPowerCalculator.java +++ b/core/java/com/android/internal/os/SensorPowerCalculator.java @@ -40,7 +40,7 @@ public class SensorPowerCalculator extends PowerCalculator { @Override protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SENSORS, + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SENSORS, calculateDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED)) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS, calculatePowerMah(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED)); diff --git a/core/java/com/android/internal/os/VideoPowerCalculator.java b/core/java/com/android/internal/os/VideoPowerCalculator.java index 5d6caf578475..0cad9a72ceec 100644 --- a/core/java/com/android/internal/os/VideoPowerCalculator.java +++ b/core/java/com/android/internal/os/VideoPowerCalculator.java @@ -39,7 +39,7 @@ public class VideoPowerCalculator extends PowerCalculator { final long durationMs = mPowerEstimator.calculateDuration(u.getVideoTurnedOnTimer(), rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); final double powerMah = mPowerEstimator.calculatePower(durationMs); - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO, durationMs) + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO, powerMah); } } diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java index 0f4767b859a3..194b6b82cd53 100644 --- a/core/java/com/android/internal/os/WakelockPowerCalculator.java +++ b/core/java/com/android/internal/os/WakelockPowerCalculator.java @@ -57,7 +57,7 @@ public class WakelockPowerCalculator extends PowerCalculator { final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); calculateApp(result, app.getBatteryStatsUid(), rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK, result.durationMs) + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah); totalAppDurationMs += result.durationMs; @@ -74,7 +74,7 @@ public class WakelockPowerCalculator extends PowerCalculator { if (osBatteryConsumer != null) { calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs, BatteryStats.STATS_SINCE_CHARGED, osPowerMah, osDurationMs, totalAppDurationMs); - osBatteryConsumer.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK, + osBatteryConsumer.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah); } diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java index 11219eccddad..ef5b147e00e4 100644 --- a/core/java/com/android/internal/os/WifiPowerCalculator.java +++ b/core/java/com/android/internal/os/WifiPowerCalculator.java @@ -100,7 +100,7 @@ public class WifiPowerCalculator extends PowerCalculator { totalAppDurationMs += powerDurationAndTraffic.durationMs; totalAppPowerMah += powerDurationAndTraffic.powerMah; - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI, + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI, powerDurationAndTraffic.durationMs); app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI, powerDurationAndTraffic.powerMah, powerModel); @@ -118,7 +118,7 @@ public class WifiPowerCalculator extends PowerCalculator { totalAppDurationMs, totalAppPowerMah, consumptionUC); systemBatteryConsumerBuilder - .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI, + .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI, powerDurationAndTraffic.durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI, totalAppPowerMah + powerDurationAndTraffic.powerMah, powerModel) diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl index 49dbbaaa17f7..a61e86bcf2a6 100644 --- a/core/java/com/android/internal/view/IInputMethodClient.aidl +++ b/core/java/com/android/internal/view/IInputMethodClient.aidl @@ -30,4 +30,5 @@ oneway interface IInputMethodClient { void reportFullscreenMode(boolean fullscreen); void updateActivityViewToScreenMatrix(int bindSequence, in float[] matrixValues); void setImeTraceEnabled(boolean enabled); + void throwExceptionFromSystem(String message); } diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 93cd4e9046c6..3b8f4405426e 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -52,9 +52,9 @@ interface IInputMethodManager { oneway void getLastInputMethodSubtype(in IInputMethodSubtypeResultCallback resultCallback); oneway void showSoftInput(in IInputMethodClient client, IBinder windowToken, int flags, - in ResultReceiver resultReceiver, in IBooleanResultCallback resultCallback); + in ResultReceiver resultReceiver, int reason, in IBooleanResultCallback resultCallback); oneway void hideSoftInput(in IInputMethodClient client, IBinder windowToken, int flags, - in ResultReceiver resultReceiver, in IBooleanResultCallback resultCallback); + in ResultReceiver resultReceiver, int reason, in IBooleanResultCallback resultCallback); // If windowToken is null, this just does startInput(). Otherwise this reports that a window // has gained focus, and if 'attribute' is non-null then also does startInput. // @NonNull @@ -68,6 +68,12 @@ interface IInputMethodManager { int unverifiedTargetSdkVersion, in IInputBindResultResultCallback inputBindResult); + oneway void reportWindowGainedFocusAsync( + boolean nextFocusHasConnection, in IInputMethodClient client, in IBinder windowToken, + /* @StartInputFlags */ int startInputFlags, + /* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode, + int windowFlags, int unverifiedTargetSdkVersion); + oneway void showInputMethodPickerFromClient(in IInputMethodClient client, int auxiliarySubtypeMode, in IVoidResultCallback resultCallback); oneway void showInputMethodPickerFromSystem(in IInputMethodClient client, diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl index c6afd78ec04b..acb4754886ab 100644 --- a/core/java/com/android/internal/view/IInputMethodSession.aidl +++ b/core/java/com/android/internal/view/IInputMethodSession.aidl @@ -43,8 +43,6 @@ oneway interface IInputMethodSession { void appPrivateCommand(String action, in Bundle data); - void toggleSoftInput(int showFlags, int hideFlags); - void finishSession(); void updateCursorAnchorInfo(in CursorAnchorInfo cursorAnchorInfo); diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index bab4e93bdd9a..4e96ae7f7903 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -128,6 +128,8 @@ public class ConversationLayout extends FrameLayout private CharSequence mFallbackChatName; private CharSequence mFallbackGroupChatName; private CharSequence mConversationTitle; + private int mMessageSpacingStandard; + private int mMessageSpacingGroup; private int mNotificationHeaderExpandedPadding; private View mConversationHeader; private View mContentContainer; @@ -241,6 +243,10 @@ public class ConversationLayout extends FrameLayout mContentContainer = findViewById(R.id.notification_action_list_margin_target); mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container); mExpandButton = findViewById(R.id.expand_button); + mMessageSpacingStandard = getResources().getDimensionPixelSize( + R.dimen.notification_messaging_spacing); + mMessageSpacingGroup = getResources().getDimensionPixelSize( + R.dimen.notification_messaging_spacing_conversation_group); mNotificationHeaderExpandedPadding = getResources().getDimensionPixelSize( R.dimen.conversation_header_expanded_padding_end); mContentMarginEnd = getResources().getDimensionPixelSize( @@ -699,6 +705,10 @@ public class ConversationLayout extends FrameLayout } private void updatePaddingsBasedOnContentAvailability() { + // groups have avatars that need more spacing + mMessagingLinearLayout.setSpacing( + mIsOneToOne ? mMessageSpacingStandard : mMessageSpacingGroup); + int messagingPadding = mIsOneToOne || mIsCollapsed ? 0 // Add some extra padding to the messages, since otherwise it will overlap with the @@ -1082,15 +1092,18 @@ public class ConversationLayout extends FrameLayout private void updateExpandButton() { int buttonGravity; - int containerHeight; ViewGroup newContainer; if (mIsCollapsed) { buttonGravity = Gravity.CENTER; - containerHeight = ViewGroup.LayoutParams.WRAP_CONTENT; + // NOTE(b/182474419): In order for the touch target of the expand button to be the full + // height of the notification, we would want the mExpandButtonContainer's height to be + // set to WRAP_CONTENT (or 88dp) when in the collapsed state. Unfortunately, that + // causes an unstable remeasuring infinite loop when the unread count is visible, + // causing the layout to occasionally hide the messages. As an aside, that naive + // solution also causes an undesirably large gap between content and smart replies. newContainer = mExpandButtonAndContentContainer; } else { buttonGravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; - containerHeight = ViewGroup.LayoutParams.MATCH_PARENT; newContainer = this; } mExpandButton.setExpanded(!mIsCollapsed); @@ -1099,7 +1112,6 @@ public class ConversationLayout extends FrameLayout // content when collapsed, but allows the content to flow under it when expanded. if (newContainer != mExpandButtonContainer.getParent()) { ((ViewGroup) mExpandButtonContainer.getParent()).removeView(mExpandButtonContainer); - mExpandButtonContainer.getLayoutParams().height = containerHeight; newContainer.addView(mExpandButtonContainer); } diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java index 7cfd46c880fc..cb1d387dbd07 100644 --- a/core/java/com/android/internal/widget/MessagingLinearLayout.java +++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java @@ -17,6 +17,7 @@ package com.android.internal.widget; import android.annotation.Nullable; +import android.annotation.Px; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; @@ -251,6 +252,16 @@ public class MessagingLinearLayout extends ViewGroup { return super.drawChild(canvas, child, drawingTime); } + /** + * Set the spacing to be applied between views. + */ + public void setSpacing(@Px int spacing) { + if (mSpacing != spacing) { + mSpacing = spacing; + requestLayout(); + } + } + @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(mContext, attrs); diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp index 04528e98212f..c32951af72e4 100644 --- a/core/jni/android_content_res_ApkAssets.cpp +++ b/core/jni/android_content_res_ApkAssets.cpp @@ -16,6 +16,8 @@ #define ATRACE_TAG ATRACE_TAG_RESOURCES +#include <mutex> + #include "signal.h" #include "android-base/logging.h" @@ -26,6 +28,7 @@ #include "utils/misc.h" #include "utils/Trace.h" +#include "android_content_res_ApkAssets.h" #include "android_util_AssetManager_private.h" #include "core_jni_helpers.h" #include "jni.h" @@ -72,6 +75,19 @@ enum : format_type_t { FORMAT_DIRECTORY = 3, }; +Guarded<std::unique_ptr<const ApkAssets>>& ApkAssetsFromLong(jlong ptr) { + return *reinterpret_cast<Guarded<std::unique_ptr<const ApkAssets>>*>(ptr); +} + +static jlong CreateGuardedApkAssets(std::unique_ptr<const ApkAssets> assets) { + auto guarded_assets = new Guarded<std::unique_ptr<const ApkAssets>>(std::move(assets)); + return reinterpret_cast<jlong>(guarded_assets); +} + +static void DeleteGuardedApkAssets(Guarded<std::unique_ptr<const ApkAssets>>& apk_assets) { + delete &apk_assets; +} + class LoaderAssetsProvider : public AssetsProvider { public: static std::unique_ptr<AssetsProvider> Create(JNIEnv* env, jobject assets_provider) { @@ -227,7 +243,7 @@ static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t forma jniThrowException(env, "java/io/IOException", error_msg.c_str()); return 0; } - return reinterpret_cast<jlong>(apk_assets.release()); + return CreateGuardedApkAssets(std::move(apk_assets)); } static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, const format_type_t format, @@ -279,7 +295,7 @@ static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, const format_type_t jniThrowException(env, "java/io/IOException", error_msg.c_str()); return 0; } - return reinterpret_cast<jlong>(apk_assets.release()); + return CreateGuardedApkAssets(std::move(apk_assets)); } static jlong NativeLoadFromFdOffset(JNIEnv* env, jclass /*clazz*/, const format_type_t format, @@ -347,12 +363,12 @@ static jlong NativeLoadFromFdOffset(JNIEnv* env, jclass /*clazz*/, const format_ jniThrowException(env, "java/io/IOException", error_msg.c_str()); return 0; } - return reinterpret_cast<jlong>(apk_assets.release()); + return CreateGuardedApkAssets(std::move(apk_assets)); } static jlong NativeLoadEmpty(JNIEnv* env, jclass /*clazz*/, jint flags, jobject assets_provider) { auto apk_assets = ApkAssets::Load(LoaderAssetsProvider::Create(env, assets_provider), flags); - return reinterpret_cast<jlong>(apk_assets.release()); + return CreateGuardedApkAssets(std::move(apk_assets)); } // STOPSHIP (b/159041693): Revert signal handler when reason for issue is found. @@ -383,54 +399,60 @@ static void DestroyErrorHandler(int sig, siginfo_t* info, void* ucontext) { } static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) { - auto apk_assets = reinterpret_cast<const ApkAssets*>(ptr); - destroy_info << "{ptr=" << apk_assets; - if (apk_assets != nullptr) { - destroy_info << ", name='" << apk_assets->GetDebugName() << "'" - << ", idmap=" << apk_assets->GetLoadedIdmap() - << ", {arsc=" << apk_assets->GetLoadedArsc(); - if (auto arsc = apk_assets->GetLoadedArsc()) { - destroy_info << ", strings=" << arsc->GetStringPool() - << ", packages=" << &arsc->GetPackages() - << " ["; - for (auto& package : arsc->GetPackages()) { - destroy_info << "{unique_ptr=" << &package - << ", package=" << package.get() << "},"; - } - destroy_info << "]"; + { + auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr)); + auto apk_assets = scoped_apk_assets->get(); + destroy_info << "{ptr=" << apk_assets; + if (apk_assets != nullptr) { + destroy_info << ", name='" << apk_assets->GetDebugName() << "'" + << ", idmap=" << apk_assets->GetLoadedIdmap() + << ", {arsc=" << apk_assets->GetLoadedArsc(); + if (auto arsc = apk_assets->GetLoadedArsc()) { + destroy_info << ", strings=" << arsc->GetStringPool() + << ", packages=" << &arsc->GetPackages() << " ["; + for (auto& package : arsc->GetPackages()) { + destroy_info << "{unique_ptr=" << &package << ", package=" << package.get() + << "},"; + } + destroy_info << "]"; + } + destroy_info << "}"; + } + destroy_info << "}"; } - destroy_info << "}"; - } - destroy_info << "}"; - delete apk_assets; + DeleteGuardedApkAssets(ApkAssetsFromLong(ptr)); - // Deleting the apk assets did not lead to a crash. - destroy_info.str(""); - destroy_info.clear(); + // Deleting the apk assets did not lead to a crash. + destroy_info.str(""); + destroy_info.clear(); } static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) { - auto apk_assets = reinterpret_cast<const ApkAssets*>(ptr); - if (auto path = apk_assets->GetPath()) { - return env->NewStringUTF(path->data()); + auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr)); + auto apk_assets = scoped_apk_assets->get(); + if (auto path = apk_assets->GetPath()) { + return env->NewStringUTF(path->data()); } return nullptr; } static jstring NativeGetDebugName(JNIEnv* env, jclass /*clazz*/, jlong ptr) { - auto apk_assets = reinterpret_cast<const ApkAssets*>(ptr); - return env->NewStringUTF(apk_assets->GetDebugName().c_str()); + auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr)); + auto apk_assets = scoped_apk_assets->get(); + return env->NewStringUTF(apk_assets->GetDebugName().c_str()); } static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) { - const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr); - return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool()); + auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr)); + auto apk_assets = scoped_apk_assets->get(); + return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool()); } static jboolean NativeIsUpToDate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) { - const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr); - return apk_assets->IsUpToDate() ? JNI_TRUE : JNI_FALSE; + auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr)); + auto apk_assets = scoped_apk_assets->get(); + return apk_assets->IsUpToDate() ? JNI_TRUE : JNI_FALSE; } static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) { @@ -439,7 +461,8 @@ static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring fil return 0; } - const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr); + auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr)); + auto apk_assets = scoped_apk_assets->get(); std::unique_ptr<Asset> asset = apk_assets->GetAssetsProvider()->Open( path_utf8.c_str(),Asset::AccessMode::ACCESS_RANDOM); if (asset == nullptr) { @@ -467,12 +490,13 @@ static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring fil static jobject NativeGetOverlayableInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring overlayable_name) { - const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr); + auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr)); + auto apk_assets = scoped_apk_assets->get(); - const auto& packages = apk_assets->GetLoadedArsc()->GetPackages(); - if (packages.empty()) { - jniThrowException(env, "java/io/IOException", "Error reading overlayable from APK"); - return 0; + const auto& packages = apk_assets->GetLoadedArsc()->GetPackages(); + if (packages.empty()) { + jniThrowException(env, "java/io/IOException", "Error reading overlayable from APK"); + return 0; } // TODO(b/119899133): Convert this to a search for the info rather than assuming it's at index 0 @@ -502,13 +526,14 @@ static jobject NativeGetOverlayableInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr } static jboolean NativeDefinesOverlayable(JNIEnv* env, jclass /*clazz*/, jlong ptr) { - const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr); - - const auto& packages = apk_assets->GetLoadedArsc()->GetPackages(); - if (packages.empty()) { - // Must throw to prevent bypass by returning false - jniThrowException(env, "java/io/IOException", "Error reading overlayable from APK"); - return 0; + auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr)); + auto apk_assets = scoped_apk_assets->get(); + + const auto& packages = apk_assets->GetLoadedArsc()->GetPackages(); + if (packages.empty()) { + // Must throw to prevent bypass by returning false + jniThrowException(env, "java/io/IOException", "Error reading overlayable from APK"); + return 0; } const auto& overlayable_infos = packages[0]->GetOverlayableMap(); diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java b/core/jni/android_content_res_ApkAssets.h index 2ae6ccd73e3d..7e525dc75ef0 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java +++ b/core/jni/android_content_res_ApkAssets.h @@ -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. @@ -14,15 +14,18 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors; +#ifndef ANDROID_CONTENT_RES_APKASSETS_H +#define ANDROID_CONTENT_RES_APKASSETS_H -/** - * System_server services that require BiometricService to load before finishing initialization - * should implement this interface. - */ -public interface BiometricServiceCallback { - /** - * Notifies the service that BiometricService is initialized. - */ - void onBiometricServiceReady(); -} +#include "androidfw/ApkAssets.h" +#include "androidfw/MutexGuard.h" + +#include "jni.h" + +namespace android { + +Guarded<std::unique_ptr<const ApkAssets>>& ApkAssetsFromLong(jlong ptr); + +} // namespace android + +#endif // ANDROID_CONTENT_RES_APKASSETS_H diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index b2c69a0aeafd..24f9abf6b814 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -42,6 +42,7 @@ #include "androidfw/ResourceTypes.h" #include "androidfw/ResourceUtils.h" +#include "android_content_res_ApkAssets.h" #include "android_util_AssetManager_private.h" #include "core_jni_helpers.h" #include "jni.h" @@ -50,9 +51,9 @@ #include "nativehelper/ScopedStringChars.h" #include "nativehelper/ScopedUtfChars.h" #include "utils/Log.h" -#include "utils/misc.h" #include "utils/String8.h" #include "utils/Trace.h" +#include "utils/misc.h" extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap); extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap); @@ -307,7 +308,9 @@ static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr, if (env->ExceptionCheck()) { return; } - apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr)); + + auto scoped_assets = ScopedLock(ApkAssetsFromLong(apk_assets_native_ptr)); + apk_assets.push_back(scoped_assets->get()); } ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index fd1b9981e8af..45e3d1b97e83 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -155,7 +155,8 @@ status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent event->getYPrecision(), event->getRawXCursorPosition(), event->getRawYCursorPosition(), - event->getDownTime(), + event->getDisplaySize().x, + event->getDisplaySize().y, event->getDownTime(), event->getHistoricalEventTime(i), event->getPointerCount(), event->getPointerProperties(), diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 832c0665488e..5acbd98822e1 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -378,7 +378,8 @@ static jlong android_view_MotionEvent_nativeInitialize( flags, edgeFlags, metaState, buttonState, static_cast<MotionClassification>(classification), transform, xPrecision, yPrecision, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, downTimeNanos, eventTimeNanos, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, + AMOTION_EVENT_INVALID_DISPLAY_SIZE, downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords); return reinterpret_cast<jlong>(event.release()); diff --git a/core/jni/include/android_runtime/AndroidRuntime.h b/core/jni/include/android_runtime/AndroidRuntime.h index d86d9340e667..bf2ba772c39d 100644 --- a/core/jni/include/android_runtime/AndroidRuntime.h +++ b/core/jni/include/android_runtime/AndroidRuntime.h @@ -19,7 +19,6 @@ #ifndef _RUNTIME_ANDROID_RUNTIME_H #define _RUNTIME_ANDROID_RUNTIME_H -#include <binder/IBinder.h> #include <jni.h> #include <pthread.h> #include <utils/Errors.h> diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto index 7d68a0df23d5..4c84944a7382 100644 --- a/core/proto/android/os/batterystats.proto +++ b/core/proto/android/os/batterystats.proto @@ -642,7 +642,7 @@ message UidProto { message ReasonCount { option (android.msg_privacy).dest = DEST_AUTOMATIC; - optional android.app.job.StopReasonEnum name = 1; + optional android.app.job.InternalStopReasonEnum name = 1; optional int32 count = 2; } repeated ReasonCount reason_count = 2; diff --git a/core/proto/android/providers/OWNERS b/core/proto/android/providers/OWNERS new file mode 100644 index 000000000000..1f5cd9a5c3b8 --- /dev/null +++ b/core/proto/android/providers/OWNERS @@ -0,0 +1 @@ +include /packages/SettingsProvider/OWNERS diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index 8ee0e397191c..c3d159659622 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -285,6 +285,7 @@ message GlobalSettingsProto { // 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 SettingProto disable_window_blurs = 9 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional Development development = 39; diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index ae6dcfdc2817..1bba12ff7fa6 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -430,6 +430,7 @@ message SecureSettingsProto { optional SettingProto one_handed_mode_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto one_handed_mode_timeout = 2 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto taps_app_to_exit = 3 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto one_handed_mode_activated = 4 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional OneHanded onehanded = 80; diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index 36d48e22e247..c4ff49cfbfaf 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -51,7 +51,7 @@ message JobSchedulerServiceDumpProto { message JobRestriction { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional .android.app.job.StopReasonEnum reason = 1; + optional .android.app.job.InternalStopReasonEnum reason = 1; optional bool is_restricting = 2; } @@ -856,7 +856,7 @@ message DataSetProto { message StopReasonCount { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional .android.app.job.StopReasonEnum reason = 1; + optional .android.app.job.InternalStopReasonEnum reason = 1; optional int32 count = 2; } repeated StopReasonCount stop_reasons = 9; @@ -907,7 +907,7 @@ message JobPackageHistoryProto { optional int32 job_id = 4; optional string tag = 5; // Only valid for STOP_JOB or STOP_PERIODIC_JOB Events. - optional .android.app.job.StopReasonEnum stop_reason = 6; + optional .android.app.job.InternalStopReasonEnum stop_reason = 6; } repeated HistoryEvent history_event = 1; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9c65dac8efb9..4dc4bef10475 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2333,6 +2333,11 @@ <permission android:name="android.permission.CAMERA_SEND_SYSTEM_EVENTS" android:protectionLevel="signature|privileged" /> + <!-- Allows injecting the external camera to replace the internal camera. + @hide --> + <permission android:name="android.permission.CAMERA_INJECT_EXTERNAL_CAMERA" + android:protectionLevel="signature" /> + <!-- =========================================== --> <!-- Permissions associated with telephony state --> <!-- =========================================== --> diff --git a/core/res/res/drawable/ic_accessibility_color_correction.xml b/core/res/res/drawable/ic_accessibility_color_correction.xml index ed09d5704ad2..f1dbfb22af53 100644 --- a/core/res/res/drawable/ic_accessibility_color_correction.xml +++ b/core/res/res/drawable/ic_accessibility_color_correction.xml @@ -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. @@ -13,40 +13,12 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector android:height="24dp" android:viewportHeight="192" - android:viewportWidth="192" android:width="24dp" - xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android"> - <path android:fillColor="#00BCD4" android:pathData="M37.14,173.74L8.61,83.77c-1.72,-5.75 0.26,-11.97 4.97,-15.63L87.15,11c5.2,-4.04 12.46,-3.99 17.61,0.12l73.81,58.94c4.63,3.7 6.53,9.88 4.8,15.57l-28.48,88.18c-1.85,6.06 -7.39,10.19 -13.67,10.19H50.84C44.53,184 38.97,179.83 37.14,173.74z"/> - <path android:fillAlpha="0.2" android:fillColor="#FFFFFF" - android:pathData="M13.58,69.14L87.15,12c5.2,-4.04 12.46,-3.99 17.61,0.12l73.81,58.94c3.36,2.68 5.27,6.67 5.41,10.82c0.15,-4.51 -1.79,-8.93 -5.41,-11.82l-73.81,-58.94C99.61,7.01 92.35,6.96 87.15,11L13.58,68.14c-3.71,2.88 -5.72,7.36 -5.56,11.94C8.17,75.85 10.14,71.81 13.58,69.14z" android:strokeAlpha="0.2"/> - <path android:fillAlpha="0.2" android:fillColor="#263238" - android:pathData="M183.35,84.63l-28.48,88.18c-1.85,6.06 -7.39,10.19 -13.67,10.19H50.84c-6.31,0 -11.87,-4.17 -13.7,-10.26L8.61,82.77c-0.36,-1.22 -0.55,-2.46 -0.59,-3.69c-0.06,1.56 0.13,3.14 0.59,4.69l28.53,89.97c1.83,6.09 7.39,10.26 13.7,10.26h90.37c6.28,0 11.82,-4.13 13.67,-10.19l28.48,-88.18c0.48,-1.57 0.67,-3.17 0.61,-4.75C183.92,82.13 183.73,83.39 183.35,84.63z" android:strokeAlpha="0.2"/> - <path android:pathData="M60.01,135L60.01,135H60l48.04,49h33.17c6.28,0 11.82,-4.13 13.67,-10.19l18.68,-57.84L129.51,72.2l-0.01,0c0.27,0.27 0.52,0.5 0.77,0.77l0.55,0.55c1.57,1.56 1.57,4.08 -0.04,5.68l-12.56,12.49l6.36,6.3l1.38,1.37l-5.67,5.64l-5.71,-5.68L79.15,135H60.42H60.01z"> - <aapt:attr name="android:fillColor"> - <gradient android:endX="155.9627" android:endY="165.1493" - android:startX="98.4649" android:startY="107.6516" android:type="linear"> - <item android:color="#19263238" android:offset="0"/> - <item android:color="#00212121" android:offset="1"/> - </gradient> - </aapt:attr> - </path> - <path android:fillColor="#0097A7" android:pathData="M68.55,120.35l32.173,-32.173l7.658,7.658l-32.173,32.173z"/> - <path android:fillColor="#FFFFFF" android:pathData="M130.83,73.52l-9.42,-9.36c-1.57,-1.56 -4.1,-1.56 -5.67,0l-12.56,12.48L95.42,69l-5.67,5.64l5.71,5.68L60,116.97V135h19.15l35.42,-35.68l5.71,5.68l5.67,-5.64l-7.73,-7.68l12.56,-12.48C132.4,77.6 132.4,75.08 130.83,73.52zM74.98,126.77l-6.43,-6.43l32.17,-32.17l6.43,6.43L74.98,126.77z"/> - <path android:fillAlpha="0.1" android:fillColor="#263238" - android:pathData="M120.28,105l-5.71,-5.68l-35.42,35.68l-19.15,0l1,1l19.15,0l35.42,-35.68l5.71,5.68l5.68,-5.64l-1,-1z" android:strokeAlpha="0.1"/> - <path android:fillAlpha="0.1" android:fillColor="#263238" - android:pathData="M90.75,75.64l-0.01,0l4.71,4.68l0.01,0z" android:strokeAlpha="0.1"/> - <path android:fillAlpha="0.1" android:fillColor="#263238" - android:pathData="M131.83,74.52l-0.97,-0.97c1.54,1.56 1.53,4.06 -0.07,5.65l-12.56,12.48l1,1l12.55,-12.48C133.4,78.6 133.4,76.08 131.83,74.52z" android:strokeAlpha="0.1"/> - <path android:fillAlpha="0.1" android:fillColor="#263238" - android:pathData="M101.72,89.17l6.67,6.66l0,0l-7.67,-7.66l-32.17,32.17l1,1z" android:strokeAlpha="0.1"/> - <path android:pathData="M37.13,173.7L8.62,83.69c-1.7,-5.8 0.3,-12 5,-15.6l73.52,-57.1c5.2,-4 12.5,-4 17.6,0.1l73.82,58.9c4.6,3.7 6.5,9.9 4.8,15.6l-28.51,88.21c-1.8,6.1 -7.4,10.2 -13.7,10.2H50.83C44.53,184 38.93,179.8 37.13,173.7z"> - <aapt:attr name="android:fillColor"> - <gradient android:centerX="21.977" android:centerY="23.8809" - android:gradientRadius="158.0384" android:type="radial"> - <item android:color="#19FFFFFF" android:offset="0"/> - <item android:color="#00FFFFFF" android:offset="1"/> - </gradient> - </aapt:attr> - </path> -</vector> + +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/accessibility_daltonizer_background" /> + <foreground> + <inset + android:drawable="@drawable/ic_accessibility_color_correction_foreground" + android:inset="@dimen/accessibility_icon_foreground_padding_ratio" /> + </foreground> +</adaptive-icon> diff --git a/core/res/res/drawable/ic_accessibility_color_correction_foreground.xml b/core/res/res/drawable/ic_accessibility_color_correction_foreground.xml new file mode 100644 index 000000000000..ecb5065163d1 --- /dev/null +++ b/core/res/res/drawable/ic_accessibility_color_correction_foreground.xml @@ -0,0 +1,26 @@ +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#ffffff" + android:fillType="evenOdd" + android:pathData="M14.8417,6.6662C14.9562,6.5573 15.0995,6.5 15.2484,6.5C15.3917,6.5 15.5349,6.5573 15.6495,6.6662L16.9901,8.0068C17.2135,8.2302 17.2135,8.5912 16.9844,8.8203L15.1969,10.6078L16.2969,11.7078L15.4891,12.5156L14.6755,11.7021L9.5651,16.8125H6.8438V14.0911L11.9542,8.9807L11.1406,8.1672L11.9484,7.3594L13.0542,8.4537L14.8417,6.6662ZM7.9896,15.6667H9.0896L13.7073,11.049L12.6073,9.949L7.9896,14.5667V15.6667Z" /> +</vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_accessibility_color_inversion.xml b/core/res/res/drawable/ic_accessibility_color_inversion.xml index d69a169d0fb3..f8558807454a 100644 --- a/core/res/res/drawable/ic_accessibility_color_inversion.xml +++ b/core/res/res/drawable/ic_accessibility_color_inversion.xml @@ -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. @@ -13,50 +13,12 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector android:height="24dp" android:viewportHeight="192" - android:viewportWidth="192" android:width="24dp" - xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android"> - <path android:fillColor="#546E7A" android:pathData="M37.14,173.74L8.61,83.77c-1.72,-5.75 0.26,-11.97 4.97,-15.63L87.15,11c5.2,-4.04 12.46,-3.99 17.61,0.12l73.81,58.94c4.63,3.7 6.53,9.88 4.8,15.57l-28.48,88.18c-1.85,6.06 -7.39,10.19 -13.67,10.19H50.84C44.53,184 38.97,179.83 37.14,173.74z"/> - <path android:fillAlpha="0.2" android:fillColor="#263238" - android:pathData="M183.37,84.63l-28.48,88.18c-1.85,6.06 -7.39,10.19 -13.67,10.19H50.84c-6.31,0 -11.87,-4.17 -13.7,-10.26L8.61,82.77c-0.36,-1.22 -0.55,-2.46 -0.59,-3.69c-0.06,1.56 0.13,3.14 0.59,4.69l28.53,89.97c1.83,6.09 7.39,10.26 13.7,10.26h90.38c6.28,0 11.82,-4.13 13.67,-10.19l28.48,-88.18c0.48,-1.57 0.67,-3.17 0.61,-4.75C183.94,82.13 183.74,83.39 183.37,84.63z" android:strokeAlpha="0.2"/> - <path android:fillAlpha="0.2" android:fillColor="#FFFFFF" - android:pathData="M13.58,69.14L87.15,12c5.2,-4.04 12.46,-3.99 17.61,0.12l73.81,58.94c3.36,2.68 5.27,6.67 5.41,10.82c0.15,-4.51 -1.79,-8.93 -5.41,-11.82l-73.81,-58.94C99.61,7.01 92.35,6.96 87.15,11L13.58,68.14c-3.71,2.88 -5.72,7.36 -5.56,11.94C8.17,75.85 10.14,71.81 13.58,69.14z" android:strokeAlpha="0.2"/> - <path android:fillAlpha="0.2" android:fillColor="#FFFFFF" - android:pathData="M53,130.05l5.03,-4.79L44.16,112c-0.05,0.78 -0.14,1.52 -0.15,2.34C43.62,136.61 61.27,154.56 84,156v-5.31C70.13,149.64 58.56,141.54 53,130.05z" android:strokeAlpha="0.2"/> - <path android:fillAlpha="0.2" android:fillColor="#FFFFFF" - android:pathData="M109,52v5.31c13.65,1.05 24.67,9.15 30.11,20.64l-4.92,4.79L147.81,96c0.09,-0.78 0.17,-1.53 0.19,-2.34C148.38,71.39 131.36,53.44 109,52z" android:strokeAlpha="0.2"/> - <path android:pathData="M154.89,173.81l13.57,-42.02l-46.53,-46.56C125.75,90.5 128,96.98 128,104c0,17.7 -14.3,32 -32,32c-8.64,0 -16.47,-3.42 -22.22,-8.97l0.9,0.91L130.73,184h10.49C147.5,184 153.04,179.87 154.89,173.81z"> - <aapt:attr name="android:fillColor"> - <gradient android:endX="153.3523" android:endY="161.6371" - android:startX="90.6075" android:startY="98.8923" android:type="linear"> - <item android:color="#33263238" android:offset="0"/> - <item android:color="#05263238" android:offset="1"/> - </gradient> - </aapt:attr> - </path> - <path android:pathData="M96,129.6V78.4c-14.11,0 -25.6,11.49 -25.6,25.6S81.89,129.6 96,129.6z"> - <aapt:attr name="android:fillColor"> - <gradient android:endX="150.8492" android:endY="164.1401" - android:startX="88.1044" android:startY="101.3954" android:type="linear"> - <item android:color="#33263238" android:offset="0"/> - <item android:color="#05263238" android:offset="1"/> - </gradient> - </aapt:attr> - </path> - <path android:fillAlpha="0.2" android:fillColor="#263238" - android:pathData="M96,136c-17.53,0 -31.72,-14.04 -31.99,-31.5c0,0.17 -0.01,0.33 -0.01,0.5c0,17.7 14.3,32 32,32s32,-14.3 32,-32c0,-0.17 -0.01,-0.33 -0.01,-0.5C127.72,121.96 113.53,136 96,136z" android:strokeAlpha="0.2"/> - <path android:fillAlpha="0.2" android:fillColor="#263238" - android:pathData="M70.4,104c0,0.17 0.01,0.33 0.01,0.5C70.68,90.62 82.06,79.4 96,79.4v-1C81.89,78.4 70.4,89.88 70.4,104z" android:strokeAlpha="0.2"/> - <path android:fillAlpha="0.2" android:fillColor="#FFFFFF" - android:pathData="M96,72c-17.7,0 -32,14.3 -32,32s14.3,32 32,32s32,-14.3 32,-32S113.7,72 96,72zM70.4,104c0,-14.11 11.49,-25.6 25.6,-25.6v51.2C81.89,129.6 70.4,118.11 70.4,104z" android:strokeAlpha="0.2"/> - <path android:fillColor="#FFFFFF" android:pathData="M96,72c-17.7,0 -32,14.3 -32,32s14.3,32 32,32s32,-14.3 32,-32S113.7,72 96,72zM70.4,104c0,-14.11 11.49,-25.6 25.6,-25.6v51.2C81.89,129.6 70.4,118.11 70.4,104z"/> - <path android:pathData="M37.14,173.74L8.61,83.77c-1.72,-5.75 0.26,-11.97 4.97,-15.63L87.15,11c5.2,-4.04 12.46,-3.99 17.61,0.12l73.81,58.94c4.63,3.7 6.53,9.88 4.8,15.57l-28.48,88.18c-1.85,6.06 -7.39,10.19 -13.67,10.19H50.84C44.53,184 38.97,179.83 37.14,173.74z"> - <aapt:attr name="android:fillColor"> - <gradient android:endX="156.2451" android:endY="171.4516" - android:startX="37.0633" android:startY="52.269802" android:type="linear"> - <item android:color="#19FFFFFF" android:offset="0"/> - <item android:color="#00FFFFFF" android:offset="1"/> - </gradient> - </aapt:attr> - </path> -</vector> + +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/accessibility_color_inversion_background" /> + <foreground> + <inset + android:drawable="@drawable/ic_accessibility_color_inversion_foreground" + android:inset="@dimen/accessibility_icon_foreground_padding_ratio" /> + </foreground> +</adaptive-icon> diff --git a/core/res/res/drawable/ic_accessibility_color_inversion_foreground.xml b/core/res/res/drawable/ic_accessibility_color_inversion_foreground.xml new file mode 100644 index 000000000000..7fc3aa686f5a --- /dev/null +++ b/core/res/res/drawable/ic_accessibility_color_inversion_foreground.xml @@ -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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="192" + android:viewportHeight="192"> + <path + android:fillAlpha="0.2" + android:fillColor="#212121" + android:pathData="M96,183L96,183c-48.23,0 -87.72,-39.33 -87.99,-87.5C8.01,95.67 8,95.83 8,96v0c0,48.4 39.6,88 88,88h0c48.4,0 88,-39.6 88,-88v0c0,-0.17 -0.01,-0.33 -0.01,-0.5C183.72,143.67 144.23,183 96,183z" /> + <path + android:fillAlpha="0.2" + android:fillColor="#FFFFFF" + android:pathData="M184,96c0,-48.4 -39.6,-88 -88,-88h0C47.6,8 8,47.6 8,96v0c0,0.17 0.01,0.33 0.01,0.5C8.28,48.33 47.77,9 96,9h0c48.23,0 87.72,39.33 87.99,87.5C183.99,96.33 184,96.17 184,96L184,96z" + android:strokeAlpha="0.2" /> + <path + android:fillAlpha="0.2" + android:fillColor="#FFFFFF" + android:pathData="M53,122.2l5.03,-4.79l-13.88,-13.26c-0.05,0.78 -0.14,1.52 -0.15,2.34c-0.39,22.27 17.27,40.22 39.99,41.66v-5.31C70.13,141.78 58.56,133.69 53,122.2z" + android:strokeAlpha="0.2" /> + <path + android:fillAlpha="0.2" + android:fillColor="#FFFFFF" + android:pathData="M109,44.15v5.31c13.65,1.05 24.67,9.15 30.11,20.64l-4.92,4.79l13.62,13.26c0.09,-0.78 0.17,-1.53 0.19,-2.34C148.38,63.53 131.36,45.59 109,44.15z" + android:strokeAlpha="0.2" /> + <path + android:fillAlpha="0.2" + android:fillColor="#263238" + android:pathData="M70.4,96.18c0,0.17 0.01,0.33 0.01,0.5c0.27,-13.88 11.64,-25.1 25.59,-25.1v-1C81.89,70.57 70.4,82.06 70.4,96.18z" + android:strokeAlpha="0.2" /> + <path + android:fillAlpha="0.2" + android:fillColor="#263238" + android:pathData="M128,96.67c-0.27,17.47 -14.46,31.5 -31.99,31.5c-8.79,0 -16.75,-3.53 -22.53,-9.26l-0.04,0l5.03,5.04c5.03,3.3 11.05,5.22 17.53,5.22c17.7,0 32,-14.31 32,-32C128.01,97.01 128,96.84 128,96.67z" + android:strokeAlpha="0.2" /> + <path + android:fillColor="#FFFFFF" + android:pathData="M96,64.16c-17.7,0 -32,14.3 -32,32c0,17.7 14.3,32 32,32c17.7,0 32,-14.3 32,-32C128,78.47 113.7,64.16 96,64.16zM70.4,96.16c0,-14.11 11.49,-25.6 25.6,-25.6v51.2C81.89,121.77 70.4,110.28 70.4,96.16z" /> +</vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_accessibility_magnification.xml b/core/res/res/drawable/ic_accessibility_magnification.xml index 5dab47951cda..f3b28877ac0f 100644 --- a/core/res/res/drawable/ic_accessibility_magnification.xml +++ b/core/res/res/drawable/ic_accessibility_magnification.xml @@ -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. @@ -13,102 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:aapt="http://schemas.android.com/aapt" - android:width="24dp" - android:height="24dp" - android:viewportWidth="192" - android:viewportHeight="192"> - <path - android:pathData="M96,104m-24,0a24,24 0,1 1,48 0a24,24 0,1 1,-48 0" - android:fillColor="#F50057"/> - <path - android:pathData="M178.57,70.06l-73.81,-58.94C99.6,7.01 92.35,6.96 87.15,11L13.59,68.14C8.87,71.8 6.9,78.02 8.61,83.77l28.53,89.97c1.83,6.09 7.39,10.26 13.7,10.26h90.38c6.28,0 11.82,-4.13 13.67,-10.19l0.69,-2.13l-34.94,-34.88v-4.7l-0.96,-0.99c-6.33,5.54 -14.61,8.9 -23.68,8.9c-19.89,0 -36.02,-16.12 -36.02,-36.01S76.11,68 96,68s36.01,16.12 36.01,36.01c0,8.68 -3.08,16.65 -8.2,22.87l1.05,1.01h4.7l30.34,30.39l23.47,-72.65C185.1,79.94 183.2,73.76 178.57,70.06z" - android:fillColor="#F50057"/> - <path - android:pathData="M65.25,73c0,0 -16.75,31.96 -9.25,45.1s21.02,29.15 40.01,32.65s32.99,10.5 39.99,14s19.58,6.93 19.58,6.93s-5.34,-9.49 4.32,-13.4c0.73,-3.53 -11.9,-42.35 -11.9,-42.35L127.92,73L81.79,62.25L65.25,73z" - android:fillColor="#F50057"/> - <path - android:pathData="M155.33,171.43l-0.44,1.37c-1.85,6.06 -7.39,10.19 -13.67,10.19H50.84c-6.31,0 -11.87,-4.17 -13.7,-10.26L8.61,82.77c-0.36,-1.22 -0.55,-2.46 -0.59,-3.69c-0.06,1.56 0.13,3.14 0.59,4.69l28.53,89.97c1.83,6.09 7.39,10.26 13.7,10.26h90.38c6.28,0 11.82,-4.13 13.67,-10.19l0.69,-2.13L155.33,171.43z" - android:strokeAlpha="0.2" - android:fillColor="#3E2723" - android:fillAlpha="0.2"/> - <path - android:pathData="M183.37,84.63l-23.71,73.41l0.24,0.24l23.47,-72.66c0.48,-1.57 0.67,-3.17 0.61,-4.75C183.94,82.13 183.74,83.39 183.37,84.63z" - android:strokeAlpha="0.2" - android:fillColor="#3E2723" - android:fillAlpha="0.2"/> - <path - android:pathData="M155.57,171.67l-34.93,-34.87v-4.7l-0.96,-0.99c-6.33,5.54 -14.61,8.9 -23.68,8.9c-9.81,0 -18.71,-3.93 -25.2,-10.29L125.07,184h16.14c6.28,0 11.81,-4.13 13.67,-10.19L155.57,171.67z"> - <aapt:attr name="android:fillColor"> - <gradient - android:startY="104.215" - android:startX="69.035" - android:endY="173.8946" - android:endX="138.7146" - android:type="linear"> - <item android:offset="0" android:color="#333E2723"/> - <item android:offset="1" android:color="#003E2723"/> - </gradient> - </aapt:attr> - </path> - <path - android:pathData="M132.01,104.01c0,8.68 -3.08,16.65 -8.2,22.87l1.05,1.01h4.7l30.34,30.39L170,127l-49,-49.03l-0.19,-0.04C127.71,84.49 132.01,93.74 132.01,104.01z"> - <aapt:attr name="android:fillColor"> - <gradient - android:startY="83.635" - android:startX="103.615" - android:endY="137.0219" - android:endX="157.0018" - android:type="linear"> - <item android:offset="0" android:color="#333E2723"/> - <item android:offset="1" android:color="#003E2723"/> - </gradient> - </aapt:attr> - </path> - <path - android:pathData="M124.27,127.32c4.85,-6.13 7.75,-13.88 7.75,-22.3c0,-0.16 -0.01,-0.31 -0.01,-0.47c-0.12,8.47 -3.17,16.24 -8.19,22.34L124.27,127.32z" - android:strokeAlpha="0.2" - android:fillColor="#3E2723" - android:fillAlpha="0.2"/> - <path - android:pathData="M96.01,80.01c-13.25,0 -24,10.75 -24,24c0,0.17 0.01,0.33 0.01,0.5c0.27,-13.02 10.91,-23.5 23.99,-23.5s23.72,10.48 23.99,23.5c0,-0.17 0.01,-0.33 0.01,-0.5C120.01,90.76 109.26,80.01 96.01,80.01z" - android:strokeAlpha="0.2" - android:fillColor="#3E2723" - android:fillAlpha="0.2"/> - <path - android:pathData="M155.58,171.68l-34.93,-34.87l0,1l34.68,34.62z" - android:strokeAlpha="0.2" - android:fillColor="#3E2723" - android:fillAlpha="0.2"/> - <path - android:pathData="M119.69,131.12c-6.33,5.54 -14.61,8.9 -23.68,8.9c-9.97,0 -19,-4.06 -25.52,-10.61h-0.01l5.59,5.59c5.71,3.8 12.57,6.03 19.94,6.03c9.07,0 17.35,-3.36 23.68,-8.9l0.96,0.99v-1L119.69,131.12z" - android:strokeAlpha="0.2" - android:fillColor="#3E2723" - android:fillAlpha="0.2"/> - <path - android:pathData="M13.59,69.14L87.15,12c5.2,-4.04 12.45,-3.99 17.61,0.12l73.81,58.94c3.36,2.68 5.27,6.67 5.41,10.82c0.15,-4.51 -1.79,-8.93 -5.41,-11.82l-73.81,-58.94C99.6,7.01 92.35,6.96 87.15,11L13.59,68.14c-3.72,2.88 -5.72,7.36 -5.57,11.94C8.17,75.85 10.14,71.81 13.59,69.14z" - android:strokeAlpha="0.2" - android:fillColor="#FFFFFF" - android:fillAlpha="0.2"/> - <path - android:pathData="M112,108h-12v12h-8v-12H80v-8h12V88h8v12h12V108z" - android:fillColor="#F8BBD0"/> - <path - android:pathData="M129.57,127.9h-4.7l-1.05,-1.01c5.12,-6.22 8.2,-14.19 8.2,-22.87c0,-19.89 -16.12,-36.01 -36.01,-36.01s-36.02,16.11 -36.02,36s16.13,36.01 36.02,36.01c9.07,0 17.35,-3.36 23.68,-8.9l0.96,0.99v4.7l34.93,34.87l4.33,-13.39L129.57,127.9zM96.01,128.01c-13.25,0 -24,-10.75 -24,-24s10.75,-24 24,-24s24,10.75 24,24S109.26,128.01 96.01,128.01z" - android:fillColor="#FFFFFF"/> - <path - android:pathData="M37.14,173.74L8.61,83.77C6.9,78.02 8.87,71.8 13.59,68.14L87.15,11c5.2,-4.04 12.45,-3.99 17.61,0.12l73.81,58.94c4.63,3.7 6.53,9.88 4.8,15.57l-28.48,88.18c-1.85,6.06 -7.39,10.19 -13.67,10.19H50.84C44.53,184 38.97,179.83 37.14,173.74z"> - <aapt:attr name="android:fillColor"> - <gradient - android:startY="53.3534" - android:startX="38.1466" - android:endY="178.712" - android:endX="163.5051" - android:type="linear"> - <item android:offset="0" android:color="#19FFFFFF"/> - <item android:offset="1" android:color="#00FFFFFF"/> - </gradient> - </aapt:attr> - </path> -</vector> + +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/accessibility_magnification_background" /> + <foreground> + <inset + android:drawable="@drawable/ic_accessibility_magnification_foreground" + android:inset="@dimen/accessibility_icon_foreground_padding_ratio" /> + </foreground> + +</adaptive-icon> diff --git a/core/res/res/drawable/ic_accessibility_magnification_foreground.xml b/core/res/res/drawable/ic_accessibility_magnification_foreground.xml new file mode 100644 index 000000000000..7ce18808fcf2 --- /dev/null +++ b/core/res/res/drawable/ic_accessibility_magnification_foreground.xml @@ -0,0 +1,26 @@ +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#ffffff" + android:fillType="evenOdd" + android:pathData="M17.6942,16.7552L14.0831,13.1441C14.5684,12.4698 14.8646,11.6568 14.8646,10.7682C14.8646,8.5058 13.0307,6.6719 10.7682,6.6719C8.5058,6.6719 6.6719,8.5058 6.6719,10.7682C6.6719,13.0307 8.5058,14.8646 10.7682,14.8646C11.6568,14.8646 12.4698,14.5684 13.1441,14.0831L16.7552,17.6942L17.6942,16.7552ZM10.7682,13.6042C9.199,13.6042 7.9323,12.3374 7.9323,10.7682C7.9323,9.199 9.199,7.9323 10.7682,7.9323C12.3374,7.9323 13.6042,9.199 13.6042,10.7682C13.6042,12.3374 12.3374,13.6042 10.7682,13.6042ZM12.6589,10.138H11.3984V8.8776H10.138V10.138H8.8776V11.3984H10.138V12.6589H11.3984V11.3984H12.6589V10.138Z" /> +</vector> diff --git a/core/res/res/drawable/ic_accessibility_reduce_bright_colors.xml b/core/res/res/drawable/ic_accessibility_reduce_bright_colors.xml new file mode 100644 index 000000000000..4eab97ba5c1a --- /dev/null +++ b/core/res/res/drawable/ic_accessibility_reduce_bright_colors.xml @@ -0,0 +1,24 @@ +<!-- + 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. +--> + +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/accessibility_feature_background" /> + <foreground> + <inset + android:drawable="@drawable/ic_accessibility_reduce_bright_colors_foreground" + android:inset="@dimen/accessibility_icon_foreground_padding_ratio" /> + </foreground> +</adaptive-icon> diff --git a/core/res/res/drawable/ic_accessibility_reduce_bright_colors_foreground.xml b/core/res/res/drawable/ic_accessibility_reduce_bright_colors_foreground.xml new file mode 100644 index 000000000000..58609dacd9b1 --- /dev/null +++ b/core/res/res/drawable/ic_accessibility_reduce_bright_colors_foreground.xml @@ -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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + <group android:scaleX="2.97" + android:scaleY="2.97" + android:translateX="18.36" + android:translateY="18.36"> + <path + android:pathData="M17,12.1L15.59,10.69L13.05,13.22V7.05H11.05V13.22L8.51,10.69L7.1,12.1L12.05,17.05L17,12.1Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M2.05,13.05H4.05C4.6,13.05 5.05,12.6 5.05,12.05C5.05,11.5 4.6,11.05 4.05,11.05H2.05C1.5,11.05 1.05,11.5 1.05,12.05C1.05,12.6 1.5,13.05 2.05,13.05Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M20.05,13.05H22.05C22.6,13.05 23.05,12.6 23.05,12.05C23.05,11.5 22.6,11.05 22.05,11.05H20.05C19.5,11.05 19.05,11.5 19.05,12.05C19.05,12.6 19.5,13.05 20.05,13.05Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M11.05,2.05V4.05C11.05,4.6 11.5,5.05 12.05,5.05C12.6,5.05 13.05,4.6 13.05,4.05V2.05C13.05,1.5 12.6,1.05 12.05,1.05C11.5,1.05 11.05,1.5 11.05,2.05Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M11.05,20.05V22.05C11.05,22.6 11.5,23.05 12.05,23.05C12.6,23.05 13.05,22.6 13.05,22.05V20.05C13.05,19.5 12.6,19.05 12.05,19.05C11.5,19.05 11.05,19.5 11.05,20.05Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M6.04,4.63C5.65,4.24 5.01,4.24 4.63,4.63C4.24,5.02 4.24,5.66 4.63,6.04L5.69,7.1C6.08,7.49 6.72,7.49 7.1,7.1C7.49,6.71 7.49,6.07 7.1,5.69L6.04,4.63Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M18.41,17C18.02,16.61 17.38,16.61 17,17C16.61,17.39 16.61,18.03 17,18.41L18.06,19.47C18.45,19.86 19.09,19.86 19.47,19.47C19.86,19.08 19.86,18.44 19.47,18.06L18.41,17Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M19.47,6.04C19.86,5.65 19.86,5.01 19.47,4.63C19.08,4.24 18.44,4.24 18.06,4.63L17,5.69C16.61,6.08 16.61,6.72 17,7.1C17.39,7.49 18.03,7.49 18.41,7.1L19.47,6.04Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M7.1,18.41C7.49,18.02 7.49,17.38 7.1,17C6.71,16.61 6.07,16.61 5.69,17L4.63,18.06C4.24,18.45 4.24,19.09 4.63,19.47C5.02,19.86 5.66,19.86 6.04,19.47L7.1,18.41Z" + android:fillColor="#ffffff"/> + </group> +</vector>
\ No newline at end of file diff --git a/core/res/res/layout/work_widget_mask_view.xml b/core/res/res/layout/work_widget_mask_view.xml index 9e1692f23a1e..e7174cc58438 100644 --- a/core/res/res/layout/work_widget_mask_view.xml +++ b/core/res/res/layout/work_widget_mask_view.xml @@ -18,7 +18,7 @@ Copyright (C) 2015 The Android Open Source Project android:id="@+id/work_widget_mask_frame" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="#F3374248" + android:background="?android:attr/colorSurfaceVariant" android:importantForAccessibility="noHideDescendants" android:clickable="true"> @@ -33,8 +33,8 @@ Copyright (C) 2015 The Android Open Source Project android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|right" - android:layout_marginBottom="4dp" - android:layout_marginRight="4dp" + android:layout_marginBottom="12dp" + android:layout_marginRight="12dp" android:src="@drawable/ic_corp_badge_off" android:clickable="false" /> </FrameLayout> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 2a28f0cdad8d..e9c5269b3b12 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarg"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Onbekende portret"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Onbekende landskap"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Gekanselleer"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Opgedateer deur jou administrateur"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Uitgevee deur jou administrateur"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte en sekere kenmerke af.\n\n"<annotation id="url">"Kom meer te wete"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte en sekere kenmerke af."</string> <string name="data_saver_description" msgid="4995164271550590517">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys voordat jy op hulle tik nie."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Skakel Databespaarder aan?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Skakel aan"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Hierdie kennisgewing is gedegradeer na Stil. Tik om terugvoer te gee."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Hierdie kennisgewing is hoër gegradeer. Tik om terugvoer te gee."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Hierdie kennisgewing is laer gegradeer. Tik om terugvoer te gee."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probeer verbeterde kennisgewings"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Skakel verbeterde kennisgewings aan sodat jy aanhou om voorgestelde handelinge, antwoorde en meer te ontvang. Android se aanpasbare kennisgewings word nie meer gesteun nie."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Skakel aan"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Nie nou nie"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Verbeterde kennisgewings"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Voorgestelde handelinge en antwoorde word nou deur verbeterde kennisgewings verskaf. Android se aanpasbare kennisgewings word nie meer gesteun nie."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Skakel af"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Kom meer te wete"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Verbeterde kennisgewings kan alle kennisgewinginhoud lees, insluitend persoonlike inligting soos kontakname en boodskappe. Hierdie kenmerk kan ook kennisgewings toemaak of handelingknoppies in kennisgewings gebruik, soos om foonoproepe te beantwoord.\n\nHierdie kenmerk kan ook Prioriteitmodus aan- of afskakel en soortgelyke instellings verander."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Verbeterde kennisgewings het Android se aanpasbare kennisgewings in Android 12 vervang. Hierdie kenmerk wys voorgestelde handelinge en antwoorde, en organiseer jou kennisgewings.\n\nVerbeterde kennisgewings het toegang tot kennisgewinginhoud, insluitend persoonlike inligting soos kontakname en -boodskappe. Hierdie kenmerk kan ook kennisgewings toemaak of daarop antwoord, soos om foonoproepe te beantwoord en Moenie Steur Nie te beheer."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Roetinemodus-inligtingkennisgewing"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery kan afloop voordat dit normaalweg gelaai word"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterybespaarder is geaktiveer om batterylewe te verleng"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Programhandelsmerkprent"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Gaan toeganginstellings na"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> kan jou skerm sien en beheer. Tik om na te gaan."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index f5a8547f0b9c..3ea2d0cc7bda 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"ሞናርክ"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"ኳርቶ"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"ፉልስካፕ"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"አር ኦ ሲ 8ኬ"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"አር ኦ ሲ 16ኬ"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"ፒ አር ሲ 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"ካሁ"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"ካኩ2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"ዩ4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"የማይታወቅ የቁም"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"የማይታወቅ የወርድ"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ተትቷል"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"በእርስዎ አስተዳዳሪ ተዘምኗል"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"እሺ"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"የባትሪ ኃይል ቆጣቢ ጠቆር ያለ ገጽታን ያበራል እና የጀርባ እንቅስቃሴን፣ አንዳንድ ምስላዊ ተጽዕኖዎችን እና የተወሰኑ ባህሪያትን ይገድባል ወይም ያጠፋል።\n\n"<annotation id="url">"የበለጠ ለመረዳት"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"የባትሪ ኃይል ቆጣቢ ጠቆር ያለ ገጽታን ያበራል እና የጀርባ እንቅስቃሴን፣ አንዳንድ ምስላዊ ተጽዕኖዎችን እና የተወሰኑ ባህሪያትን ይገድባል ወይም ያጠፋል።"</string> <string name="data_saver_description" msgid="4995164271550590517">"የውሂብ አጠቃቀም እንዲቀንስ ለማገዝ ውሂብ ቆጣቢ አንዳንድ መተግበሪያዎች ከበስተጀርባ ሆነው ውሂብ እንዳይልኩ ወይም እንዳይቀበሉ ይከለክላቸዋል። በአሁኑ ጊዜ እየተጠቀሙበት ያለ መተግበሪያ ውሂብ ሊደርስ ይችላል፣ ነገር ግን ባነሰ ተደጋጋሚነት ሊሆን ይችላል። ይሄ ማለት ለምሳሌ ምስሎችን መታ እስኪያደርጓቸው ድረስ ላይታዩ ይችላሉ ማለት ነው።"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ውሂብ ቆጣቢ ይጥፋ?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"አብራ"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ይህ ማሳወቂያ ወደ ዝምታ ዝቅ ብሏል። ግብረመልስ ለመስጠት መታ ያድርጉ።"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ይህ ማሳወቂያ ከፍተኛ ደረጃ ተሰጥቶታል። ግብረመልስ ለመስጠት መታ ያድርጉ።"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ይህ ማሳወቂያ ዝቅተኛ ደረጃ ተሰጥቶታል። ግብረመልስ ለመስጠት መታ ያድርጉ።"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"የተሻሻሉ ማሳወቂያዎችን ይሞክሩ"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"የተጠቆሙ እርምጃዎችን፣ ምላሾችን እና ሌሎችን ማግኘትን ለመቀጠል የተሻሻሉ ማሳወቂያዎችን ያብሩ። የAndroid አስማሚ ማሳወቂያዎች ከአሁን በኋላ አይደገፉም።"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"አብራ"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"አሁን አይደለም"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"የተሻሻሉ ማሳወቂያዎች"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"የተጠቆሙ እርምጃዎች እና ምላሾች አሁን በተሻሻሉ ማሳወቂያዎች ቀርበዋል። የAndroid አስማሚ ማሳወቂያዎች ከእንግዲህ አይደገፉም።"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"እሺ"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"አጥፋ"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"የበለጠ ለመረዳት"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"የተሻሻሉ ማሳወቂያዎች እንደ የእውቂያ ስሞች እና መልዕክቶች ያሉ የግል መረጃዎችን ጨምሮ ሁሉንም የማሳወቂያ ይዘቶችን ማንበብ ይችላሉ። ይህ ባህሪ ማሳወቂያዎችን ማሰናከል ወይም እንደ የስልክ ጥሪዎችን ማንሳት በመሳሰሉ ማሳወቂያዎች ውስጥ ባሉ አዝራሮች ላይ እርምጃዎችንም አዝራሮች ላይ እርምጃዎችንም መውሰድ ይችላል።\n\nይህ ባህሪ የቅድሚያ ሁነታን ማብራት ወይም ማጥፋት እና ተዛማጅ ቅንብሮችን መለወጥ ይችላል።"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"የተሻሻሉ ማሳወቂያዎች በAndroid 12 ውስጥ Android ራስ-አስማሚ ማሳወቂያዎችን ተክተዋል። ይህ ባህሪ የተጠቆሙ እርምጃዎችን እና ምላሾችን ያሳያል እንዲሁም ማሳወቂያዎችዎን ያደራጃል።\n\nየተሻሻሉ ማሳወቂያዎች እንደ የእውቂያ ስሞች እና መልዕክቶች ያሉ የግል መረጃዎችን ጨምሮ የማሳወቂያ ይዘቶችን መድረስ ይችላሉ። ይህ ባህሪ እንደ የስልክ ጥሪዎችን መመለስ እና አትረብሽን መቆጣጠርን ያሉ ማሳወቂያዎችን ማሰናበት ወይም ምላሽ መስጠት ይችላል።"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"የዕለት ተዕለት ሁነታ መረጃ ማሳወቂያዎች"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ባትሪ ከተለመደው ኃይል መሙላት በፊት ሊያልቅ ይችላል"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"የባትሪ ቆጣቢ የባትሪ ዕድሜን ለማራዘም ገብሯል።"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"የመተግበሪያ የምርት ስም ምስል"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"የመዳረሻ ቅንብሮችን ይፈትሹ"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ማያ ገጽዎን ማየት እና መቆጣጠር ይችላል። ለመገምገም መታ ያድርጉ።"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 984069a0fd85..cf3968d634c7 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1861,28 +1861,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"فولسكاب"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1919,8 +1908,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"عمودي غير معروف"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"أفقي غير معروف"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ملغاة"</string> @@ -1968,10 +1956,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"تم التحديث بواسطة المشرف"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"تم الحذف بواسطة المشرف"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"حسنًا"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"يؤدي استخدام خيار \"توفير شحن البطارية\" إلى تفعيل \"المظهر الداكن\" وتقييد أو إيقاف الأنشطة في الخلفية وبعض التأثيرات المرئية وميزات معيّنة.\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"يؤدي استخدام خيار \"توفير شحن البطارية\" إلى تفعيل \"المظهر الداكن\" وتقييد أو إيقاف الأنشطة في الخلفية وبعض التأثيرات المرئية وميزات معيّنة."</string> <string name="data_saver_description" msgid="4995164271550590517">"للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيقات المتاحة لديك الآن استخدام البيانات، ولكن لا يمكنها الإكثار من ذلك. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"هل تريد تفعيل توفير البيانات؟"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"تفعيل"</string> @@ -2231,12 +2217,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"تم خفض ترتيب هذا الإشعار إلى الوضع \"صامت\". انقر لإرسال ملاحظات وآراء."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"تمت زيادة ترتيب هذا الإشعار. انقر لإرسال ملاحظات وآراء."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"تم خفض ترتيب هذا الإشعار. انقر لإرسال ملاحظات وآراء."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"تجربة الإشعارات المحسّنة"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"لمواصلة الحصول على الردود والإجراءات المقترحة والمزيد، عليك تفعيل الإشعارات المحسّنة. لم تعد الإشعارات التكيُّفية لنظام التشغيل Android متاحة."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"تفعيل"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"لاحقًا"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"الإشعارات المحسّنة"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"يتم الآن توفير الإجراءات والردود المقترحة من خلال الإشعارات المحسّنة. ولم تعد الإشعارات التكيُّفية لنظام التشغيل Android متاحة."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"حسنًا"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"إيقاف"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"مزيد من المعلومات"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"يمكن للإشعارات المحسّنة قراءة كل محتوى الإشعارات، بما في ذلك المعلومات الشخصية، مثلاً أسماء جهات الاتصال والرسائل. يمكن لهذه الميزة أيضًا إغلاق الإشعارات أو اتخاذ إجراءات من خلال الأزرار في الإشعارات، مثلاً الردّ على مكالمات الهاتف.\n\nويمكن لهذه الميزة أيضًا تفعيل وضع \"الأولوية\" أو إيقافه وتغيير الإعدادات ذات الصلة."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"تم إبدال الإشعارات المحسّنة بالإشعارات التكيُّفية لنظام التشغيل Android في الإصدار 12 منه. تعرض هذه الميزة إجراءات وردودًا مقترحة وتنظِّم الإشعارات.\n\nيمكن للإشعارات المحسّنة الوصول إلى محتوى الإشعارات، بما في المعلومات الشخصية، مثلاً أسماء جهات الاتصال والرسائل. يمكن لهذه الميزة أيضًا إغلاق الإشعارات أو الاستجابة لها، مثلاً الردّ على مكالمات الهاتف والتحكّم في ميزة \"عدم الإزعاج\"."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"إشعار معلومات \"وضع سلسلة الإجراءات\""</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"قد تنفد طاقة البطارية قبل الشحن المعتاد"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"تم تفعيل \"توفير شحن البطارية\" لإطالة عمرها."</string> @@ -2437,4 +2423,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"الصورة الذهنية للعلامة التجارية للتطبيق"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"التحقّق من إعدادات الوصول"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"يمكن لخدمة <xliff:g id="SERVICE_NAME">%s</xliff:g> الاطّلاع على شاشتك والتحكّم فيها. انقر لمراجعة الإعدادات."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 7d86f6c7afa5..182fddce11b0 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -1708,7 +1708,7 @@ <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"শ্বৰ্টকাট অফ কৰক"</string> <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="color_correction_feature_name" msgid="3655077237805422597">"ৰং শুধৰণি"</string> <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"এক্সট্ৰা ডিম"</string> <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> @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"ম\'নাৰ্ক"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"কুৱাট্ৰো"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"ফুলস্কেপ"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"অজ্ঞাত প\'ৰ্ট্ৰেইট"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"অজ্ঞাত লেণ্ডস্কেইপ"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"বাতিল কৰা হ’ল"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"আপোনাৰ প্ৰশাসকে আপেডট কৰিছে"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"আপোনাৰ প্ৰশাসকে মচিছে"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে আৰু নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট আৰু নিৰ্দিষ্ট কিছুমান সুবিধা সীমিত অথবা অফ কৰে।\n\n"<annotation id="url">"অধিক জানক"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে আৰু নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট আৰু নিৰ্দিষ্ট কিছুমান সুবিধা সীমিত অথবা অফ কৰে।"</string> <string name="data_saver_description" msgid="4995164271550590517">"ডেটা ব্য়ৱহাৰৰ হ্ৰাস কৰিবলৈ ডেটা সঞ্চয়কাৰীয়ে কিছুমান এপক নেপথ্য়ত ডেটা প্ৰেৰণ বা সংগ্ৰহ কৰাত বাধা প্ৰদান কৰে। আপুনি বৰ্তমান ব্য়ৱহাৰ কৰি থকা এটা এপে ডেটা এক্সেছ কৰিব পাৰে, কিন্তু সঘনাই এক্সেছ কৰিব নোৱাৰিব পাৰে। ইয়াৰ অৰ্থ উদাহৰণস্বৰূপে এয়া হ\'ব পাৰে যে, আপুনি নিটিপা পর্যন্ত প্ৰতিচ্ছবিসমূহ দেখুওৱা নহ’ব।"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সঞ্চয়কাৰী অন কৰিবনে?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"অন কৰক"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"এই জাননীটোৰ গুৰুত্ব নীৰৱলৈ হ্ৰাস কৰা হৈছে। মতামত দিবলৈ টিপক।"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"এই জাননীটোৰ স্থান ওপৰলৈ কৰা হৈছে। মতামত দিবলৈ টিপক।"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"এই জাননীটোৰ স্থান তললৈ কৰা হৈছে। মতামত দিবলৈ টিপক।"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"উন্নত জাননী ব্যৱহাৰ কৰি চাওক"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"পৰামৰ্শ দিয়া কাৰ্য, প্ৰত্যুত্তৰ আৰু বহুতো সুবিধা পাই থাকিবলৈ উন্নত জাননী অন কৰক। Androidৰ অভিযোজিত জাননী আৰু সমৰ্থিত নহয়।"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"অন কৰক"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"এতিয়া নহয়"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"উন্নত জাননী"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"এতিয়া উন্নত জাননীয়ে পৰামৰ্শ দিয়া কাৰ্য আৰু প্ৰত্যুত্তৰ প্ৰদান কৰে। Androidৰ অভিযোজিত জাননী আৰু সমৰ্থিত নহয়।"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ঠিক আছে"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"অফ কৰক"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"অধিক জানক"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"উন্নত প্ৰত্যুত্তৰে সম্পৰ্কৰ নাম আৰু বাৰ্তাৰ দৰে ব্যক্তিগত তথ্যৰ লগতে আটাইবোৰ জাননীৰ সমল পঢ়িব পাৰে। এই সুবিধাটোৱে জাননী অগ্ৰাহ্য কৰাৰ লগতে জাননীত থকা ফ’ন কলৰ উত্তৰ দিয়াৰ দৰে কাৰ্য বুটামৰ ওপৰত কাৰ্যব্যৱস্থা ল’ব পাৰে।\n\nলগতে, এই সুবিধাটোৱে অগ্ৰাধিকাৰ দিয়া ম’ড অন অথবা অফ কৰিব পাৰে আৰু সম্পৰ্কিত ছেটিং সলনি কৰিব পাৰে।"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12ত Androidৰ অভিযোজিত জাননীক উন্নত জাননীৰ দ্বাৰা সলনি কৰা হৈছে। এই সুবিধাটোৱে পৰামৰ্শ দিয়া কাৰ্য আৰু প্ৰত্যুত্তৰ দেখুৱায় আৰু আপোনাৰ জাননীসমূহ শৃংখলাবদ্ধ কৰে।\n\nউন্নত জাননীয়ে সম্পৰ্কৰ নাম আৰু বাৰ্তাৰ দৰে ব্যক্তিগত তথ্যকে ধৰি জাননীৰ সমল এক্সেছ কৰিব পাৰে। এই সুবিধাটোৱে জাননী অগ্ৰাহ্য কৰিব অথবা জাননীৰ প্ৰতি সঁহাৰি জনাবও পাৰে, যেনে ফ’ন কলৰ উত্তৰ দিয়া আৰু অসুবিধা নিদিব সুবিধাটো নিয়ন্ত্ৰণ কৰা আদি।"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ৰুটিন ম’ডৰ তথ্য জাননী"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"চ্চাৰ্জ কৰাৰ সচৰাচৰ সময়ৰ আগতেই বেটাৰি শেষ হ’ব পাৰে"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"বেটাৰিৰ খৰচ কমাবলৈ বেটাৰি সঞ্চয়কাৰী অন কৰা হৈছে"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"এপ্লিকেশ্বনৰ ব্ৰেণ্ডৰ প্ৰতিচ্ছবি"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"এক্সেছৰ ছেটিং পৰীক্ষা কৰক"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g>এ আপোনাৰ স্ক্ৰীনখন চাব আৰু পৰিচালনা কৰিব পাৰে। পৰ্যালোচনা কৰিবলৈ টিপক।"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 3dba1f9ebf8c..12daa990d696 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Naməlum portret"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Naməlum mənzərə"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Ləğv edildi"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Admin tərəfindən yeniləndi"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Admin tərəfindən silindi"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Enerjiyə Qənaət Qaranlıq temanı aktiv edir, arxa fondakı fəaliyyətlər, bəzi vizual effektlər və müəyyən funksiyaları məhdudlaşdırır və ya deaktiv edir.\n\n"<annotation id="url">"Ətraflı məlumat"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Enerjiyə Qənaət Qaranlıq temanı aktiv edir, arxa fondakı fəaliyyətlər, bəzi vizual effektlər və müəyyən funksiyaları məhdudlaşdırır və ya deaktiv edir."</string> <string name="data_saver_description" msgid="4995164271550590517">"Mobil interneti qənaətlə işlətmək məqsədilə Data Qanaəti bəzi tətbiqlərin fonda data göndərməsinin və qəbulunun qarşısını alır. Hazırda işlətdiyiniz tətbiq nisbətən az müntəzəmliklə data istifadə edə bilər. Örnək olaraq bu, o deməkdir ki, şəkil fayllarına toxunmadıqca onlar açılmayacaq."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Trafikə qənaət edilsin?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivləşdirin"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Bu bildiriş Səssiz rejimə keçirilib. Rəy bildirmək üçün toxunun."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Bu bildiriş yuxarı sıraya keçirilib. Rəy bildirmək üçün toxunun."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Bu bildiriş aşağı sıraya keçirilib. Rəy bildirmək üçün toxunun."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Genişləndirilmiş bildirişləri sınayın"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Təklif olunan əməliyyatlar, cavablar və daha çoxunu almağa davam etmək üçün genişləndirilmiş bildirişləri aktiv edin. Android Adaptiv Bildirişləri artıq dəstəklənmir."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktiv edin"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"İndi yox"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Genişləndirilmiş bildirişlər"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Təklif olunan əməliyyatlar və cavablar artıq genişləndirilmiş bildirişlər tərəfindən təmin olunur. Android Adaptiv Bildirişləri artıq dəstəklənmir."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Deaktiv edin"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Ətraflı məlumat"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Genişləndirilmiş bildirişlər, kontakt adları və mesajlar kimi şəxsi məlumatlar daxil olmaqla bütün bildiriş məzmununu oxuya bilər. Bu funksiya həmçinin bildirişləri qapada və ya telefon zənglərinə cavab vermək kimi bildirişlərdəki düymələr üzərində əməliyyatlar edə bilər.\n\nBu funksiya həmçinin Prioritet rejimini aktiv və ya deaktiv edə və əlaqəli ayarları dəyişdirə bilər."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Genişləndirilmiş bildirişlər Android 12-də Android Adaptiv Bildirişləri əvəz etdi. Bu funksiya təklif olunan əməliyyatları və cavabları göstərir və bildirişlərinizi təşkil edir.\n\nGenişləndirilmiş bildirişlər, kontakt adları və mesajlar kimi şəxsi məlumatlar daxil olmaqla bütün bildiriş məzmununa giriş edə bilər. Bu funksiya telefon zənglərinə cavab vermək və Narahat Etməyin rejimini idarə etmək kimi bildirişləri qapada və ya cavablandıra bilər."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rejim üçün məlumat bildirişi"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batareya həmişəki vaxtdan əvvəl bitə bilər"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Enerjiyə Qənaət rejimi batareya istifadəsinin müddətini artırmaq üçün aktiv edilir"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Tətbiqin brend şəkli"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Giriş ayarlarını yoxlayın"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ekranınıza baxa və nəzarət edə bilər. Nəzərdən keçirmək üçün toxunun."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <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 86f60a830ba5..3bb3f33251b5 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1842,8 +1842,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Nepoznata veličina, uspravno"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Nepoznata veličina, vodoravno"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Otkazano je"</string> @@ -1888,10 +1887,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je administrator"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je administrator"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Potvrdi"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizuelne efekte i određene funkcije.\n\n"<annotation id="url">"Saznajte više"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizuelne efekte i određene funkcije."</string> <string name="data_saver_description" msgid="4995164271550590517">"Da bi se smanjila potrošnja podataka, Ušteda podataka sprečava neke aplikacije da šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može da pristupa podacima, ali će to činiti ređe. Na primer, slike se neće prikazivati dok ih ne dodirnete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Želite da uključite Uštedu podataka?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string> @@ -2121,12 +2118,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Ovo obaveštenje je degradirano u Nečujno. Dodirnite da biste naveli povratne informacije."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Ovo obaveštenje je rangirano više. Dodirnite da biste naveli povratne informacije."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Ovo obaveštenje je rangirano niže. Dodirnite da biste naveli povratne informacije."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probajte poboljšana obaveštenja"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Uključite poboljšana obaveštenja da biste i dalje dobijali preporučene radnje, odgovore i drugo. Prilagodljiva obaveštenja za Android više nisu podržana."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Uključi"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ne sada"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Poboljšana obaveštenja"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Predložene radnje i odgovore sada dobijate pomoću poboljšanih obaveštenja. Prilagodljiva obaveštenja za Android više nisu podržana."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Potvrdi"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Isključi"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saznajte više"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Poboljšana obaveštenja mogu da čitaju sadržaj svih obaveštenja, uključujući lične podatke, poput imena kontakata i poruka. Ova funkcija može i da odbacuje obaveštenja ili aktivira dugmad u obaveštenjima, poput javljanja na telefonske pozive.\n\nOva funkcija može i da uključi ili isključi Prioritetni režim i da menja povezana podešavanja."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Poboljšana obaveštenja su zamenila Android prilagodljiva obaveštenja u Android-u 12. Ova funkcija pokazuje predložene radnje i odgovore i organizuje obaveštenja.\n\nPoboljšana obaveštenja mogu da pristupaju sadržaju obaveštenja, uključujući lične informacije poput imena kontakata i poruka. Ova funkcija može i da odbacuje obaveštenja ili da odgovara na njih, na primer, da se javlja na telefonske pozive i kontroliše režim Ne uznemiravaj."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obaveštenje o informacijama Rutinskog režima"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterija će se možda isprazniti pre uobičajenog punjenja"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Ušteda baterije je aktivirana da bi se produžilo trajanje baterije"</string> @@ -2324,4 +2321,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imidž brenda aplikacije"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Proverite podešavanja pristupa"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> može da pregleda i kontroliše ekran. Dodirnite da biste pregledali."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 1f6088abd32a..7db01d10f753 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -1817,28 +1817,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1875,8 +1864,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Невядомы (кніжная арыентацыя)"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Невядомы (альбомная арыентацыя)"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Скасавана"</string> @@ -1922,10 +1910,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Абноўлены вашым адміністратарам"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Выдалены вашым адміністратарам"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"У рэжыме эканоміі зараду ўключаецца цёмная тэма і выключаюцца ці абмяжоўваюцца дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і пэўныя функцыі.\n\n"<annotation id="url">"Даведацца больш"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"У рэжыме эканоміі зараду ўключаецца цёмная тэма і выключаюцца ці абмяжоўваюцца дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і пэўныя функцыі."</string> <string name="data_saver_description" msgid="4995164271550590517">"У рэжыме \"Эканомія трафіка\" фонавая перадача для некаторых праграмам адключана. Праграма, якую вы зараз выкарыстоўваеце, можа атрымліваць доступ да даных, але радзей, чым звычайна. Напрыклад, відарысы могуць не загружацца, пакуль вы не націсніце на іх."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Уключыць Эканомію трафіка?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Уключыць"</string> @@ -2165,12 +2151,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Гэта апавяшчэнне пераведзена ў рэжым \"Без гуку\". Націсніце тут і дайце водгук."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Гэта апавяшчэнне ацэнена як важнае. Націсніце тут і дайце водгук."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Гэта апавяшчэнне ацэнена як няважнае. Націсніце тут і дайце водгук."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Палепшаныя апавяшчэнні"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Каб і далей атрымліваць прапановы дзеянняў, адказаў і іншага змесціва, уключыце палепшаныя апавяшчэнні. Адаптыўныя апавяшчэнні Android больш не падтрымліваюцца."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Уключыць"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не зараз"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Палепшаныя апавяшчэнні"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Прапановы дзеянняў і адказаў цяпер даюцца ў выглядзе палепшаных апавяшчэнняў. Адаптыўныя апавяшчэнні Android больш не падтрымліваюцца."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ОК"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Выключыць"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Даведацца больш"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Палепшаныя апавяшчэнні маюць доступ да змесціва ўсіх апавяшчэнняў, у тым ліку да асабістай інфармацыі – імён кантактаў і паведамленняў. Гэта функцыя таксама можа адхіляць апавяшчэнні ці актываваць у іх кнопкі дзеянняў, у тым ліку адказваць на тэлефонныя выклікі.\n\nГэта функцыя можа ўключаць і выключаць прыярытэтны рэжым, а таксама змяняць звязаныя налады."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"У версіі Android 12 Адаптыўныя апавяшчэнні Android заменены Палепшанымі апавяшчэннямі. Гэта функцыя ўпарадкоўвае вашы апавяшчэнні і паказвае прапановы дзеянняў і адказаў.\n\nПалепшаныя апавяшчэнні маюць доступ да змесціва ўсіх апавяшчэнняў, у тым ліку да асабістай інфармацыі – імён кантактаў і паведамленняў. Яшчэ гэта функцыя можа адхіляць апавяшчэнні ці адказваць на іх, напрыклад рэагаваць на тэлефонныя выклікі і кіраваць функцыяй \"Не турбаваць\"."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Апавяшчэнне з інфармацыяй пра ўсталяваны рэжым"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Акумулятар можа разрадзіцца хутчэй, чым прыйдзе час звычайнай зарадкі"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Каб павялічыць тэрмін работы акумулятара, уключаны рэжым эканоміі зараду"</string> @@ -2369,4 +2355,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Відарыс брэнда праграмы"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Праверце налады доступу"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> можа праглядаць экран вашай прылады і кіраваць ім. Націсніце, каб праглядзець."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 7f17c2c7e01e..5a327ce20c91 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Неизвестен вертикален формат"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Неизвестен хоризонтален формат"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Анулирано"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Актуализирано от администратора ви"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Изтрито от администратора ви"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Режимът за запазване на батерията включва тъмната тема и ограничава или изключва активността на заден план, някои визуални ефекти и определени функции.\n\n"<annotation id="url">"Научете повече"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Режимът за запазване на батерията включва тъмната тема и ограничава или изключва активността на заден план, някои визуални ефекти и определени функции."</string> <string name="data_saver_description" msgid="4995164271550590517">"С цел намаляване на преноса на данни функцията за икономия на данни не позволява на някои приложения да изпращат или получават данни на заден план. Понастоящем използвано от вас приложение може да използва данни, но по-рядко. Това например може да означава, че изображенията не се показват, докато не ги докоснете."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Включване на „Икономия на данни“?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Включване"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Това известие бе понижено до беззвучно. Докоснете, за да изпратите отзиви."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Това известие бе класирано по-високо. Докоснете, за да изпратите отзиви."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Това известие бе класирано по-ниско. Докоснете, за да изпратите отзиви."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Изпробвайте подобрен. известия"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"За да продължите да получавате предложени действия, отговори и др., включете функцията за подобрени известия. Адаптивните известия за Android вече не се поддържат."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Включване"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не сега"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Подобрени известия"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Предложените действия и отговори вече се предоставят от функцията за подобрени известия. Адаптивните известия за Android вече не се поддържат."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Изключване"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Научете повече"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Функцията за подобрени известия може да чете цялото съдържание в дадено известие, включително личната информация, като например имената на контактите и текстовите съобщения. Тя има възможност да отхвърля известията или да предприема действия по бутоните в тях, като например приемане на телефонни обаждания.\n\nСъщо така функцията може да включва или изключва приоритетния режим и да променя сродни настройки."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Адаптивните известия бяха заменени от функцията за подобрени известия в Android 12. Тя показва предложени действия и отговори и организира известията ви.\n\nФункцията може да осъществява достъп до съдържанието в известията, включително личната информация, като например имената на контактите и текстовите съобщения. Тя има възможност да отхвърля известията или да предприема действия в тях, като например приемане на телефонни обаждания или контролиране на режима „Не безпокойте“."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Известие с информация за режима на поредица"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батерията може да се изтощи преди обичайното зареждане"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Режимът за запазване на батерията е активиран с цел удължаване на живота на батерията"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Изображение на търговската марка на приложението"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Проверете настройките за достъп"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> може да преглежда и управлява съдържанието на екрана ви. Докоснете за преглед."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 04cdcf574abc..a265821e5b09 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"অজানা পোর্ট্রেট"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"অজানা ল্যান্ডস্কেপ"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"বাতিল করা হয়েছে"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"আপনার প্রশাসক আপডেট করেছেন"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"আপনার প্রশাসক মুছে দিয়েছেন"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ব্যাটারি সেভার ডার্ক থিম চালু করে এবং ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট ও নির্দিষ্ট ফিচারের ব্যবহার সীমিত করে বা বন্ধ করে দেয়।\n\n"<annotation id="url">"আরও জানুন"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"ব্যাটারি সেভার ডার্ক থিম চালু করে এবং ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট ও নির্দিষ্ট ফিচারের ব্যবহার সীমিত করে বা বন্ধ করে দেয়।"</string> <string name="data_saver_description" msgid="4995164271550590517">"ডেটার ব্যবহার কমাতে সহায়তা করার জন্য, ডেটা সেভার ব্যাকগ্রাউন্ডে কিছু অ্যাপ্লিকেশনকে ডেটা পাঠাতে বা গ্রহণ করতে বাধা দেয়৷ আপনি বর্তমানে এমন একটি অ্যাপ্লিকেশন ব্যবহার করছেন যেটি ডেটা অ্যাক্সেস করতে পারে, তবে সেটি কমই করে৷ এর ফলে যা হতে পারে, উদাহরণস্বরূপ, আপনি ছবির উপর ট্যাপ না করা পর্যন্ত সেগুলি দেখানো হবে না৷"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সেভার চালু করবেন?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"চালু করুন"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"এই বিজ্ঞপ্তির গুরুত্ব কমিয়ে মিউট হিসেবে সেট করা হয়েছে। মতামত জানাতে ট্যাপ করুন।"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"এই বিজ্ঞপ্তির গুরুত্ব বাড়ানো হয়েছে। মতামত জানাতে ট্যাপ করুন।"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"এই বিজ্ঞপ্তির গুরুত্ব কমানো হয়েছে। মতামত জানাতে ট্যাপ করুন।"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"উন্নত নোটিফিকেশন ব্যবহার করুন"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"সাজেস্ট করা অ্যাকশন, উত্তর এবং আরও অনেক কিছু পাওয়া চালিয়ে যেতে, উন্নত নোটিফিকেশন পাওয়ার সুবিধা চালু করুন। Android অ্যাডাপ্টিভ নোটিফিকেশন আর কাজ করবে না।"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"চালু করুন"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"এখন নয়"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"উন্নত বিজ্ঞপ্তি"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"সাজেস্ট করা অ্যাকশন এবং উত্তর এখন উন্নত বিজ্ঞপ্তির মাধ্যমে পাওয়া যায়। Android অ্যাডাপ্টিভ বিজ্ঞপ্তি আর কাজ করবে না।"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ঠিক আছে"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"বন্ধ করুন"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"আরও জানুন"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"উন্নত নোটিফিকেশন পরিচিতির নাম এবং মেসেজের মতো ব্যক্তিগত তথ্য ছাড়াও নোটিফিকেশনের সবকটি কন্টেন্ট পড়তে পারবে। এছাড়াও, এই ফিচার নোটিফিকেশন বাতিল করতে পারবে এবং নোটিফিকেশনে থাকা বোতামের সাহায্যে অ্যাকশন নিতে পারবে, যেমন ফোন কলের উত্তর দেওয়া।\n\nএই ফিচার প্রায়োরিটি মোড চালু বা বন্ধ করতে এবং সেই সম্পর্কিত সেটিংস পরিবর্তনও করতে পারবে।"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 ভার্সনে Android অ্যাডাপ্টিভ বিজ্ঞপ্তির পরিবর্তে উন্নত বিজ্ঞপ্তি এসেছে। এই ফিচারটি সাজেস্ট করা অ্যাকশন ও উত্তর দেখায় এবং আপনার বিজ্ঞপ্তি এক জায়াগায় সাজিয়ে রাখে। \n\nউন্নত বিজ্ঞপ্তি পরিচিতির নাম এবং মেসেজের মতো ব্যক্তিগত তথ্য ছাড়াও বিজ্ঞপ্তির কন্টেন্ট অ্যাক্সেস করতে পারে। এছাড়া, এই ফিচার বিজ্ঞপ্তি বাতিল করতে বা তার উত্তর দিতে পারে, যেমন ফোন কলের উত্তর দেওয়া এবং \'বিরক্ত করবে না\' মোড নিয়ন্ত্রণ করা।"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"রুটিন মোডের তথ্য সংক্রান্ত বিজ্ঞপ্তি"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"সাধারণত যখন চার্জ দেন, তার আগে চার্জ শেষ হয়ে যেতে পারে"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ডিভাইস বেশিক্ষণ চালু রাখতে ব্যাটারি সেভার চালু করা হয়েছে"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"অ্যাপের ব্র্যান্ড ছবি"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"অ্যাক্সেস করার সেটিংস চেক করুন"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> আপনার স্ক্রিন দেখতে ও কন্ট্রোল করতে পারবে। পর্যালোচনা করতে ট্যাপ করুন।"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index dd00bd0fb453..30a2ccc9e99c 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -1842,8 +1842,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Neodređeni uspravni format"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Neodređeni vodoravni format"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Otkazano"</string> @@ -1888,10 +1887,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je vaš administrator"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je vaš administrator"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Uredu"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i neke funkcije.\n\n"<annotation id="url">"Saznajte više"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i neke funkcije."</string> <string name="data_saver_description" msgid="4995164271550590517">"Radi smanjenja prijenosa podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali će to činiti rjeđe. Naprimjer, to može značiti da se slike ne prikazuju dok ih ne dodirnete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Uključiti Uštedu podataka?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string> @@ -2121,12 +2118,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Značaj ovog obavještenja je umanjen na Nečujno. Dodirnite da pošaljete povratne informacije."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Značaj ovog obavještenja je povećan. Dodirnite da pošaljete povratne informacije."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Značaj ovog obavještenja je umanjen. Dodirnite da pošaljete povratne informacije."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probajte poboljšana obavještenja"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Da nastavite primati prijedloge radnji, odgovore i još mnogo toga, uključite poboljšana obavještenja. Prilagodljiva obavještenja Androida više nisu podržana."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Uključi"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ne sada"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Poboljšana obavještenja"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Poboljšana obavještenja sada pružaju predložene radnje i odgovore. Prilagodljiva obavještenja Androida više nisu podržana."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Uredu"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Isključi"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saznajte više"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Poboljšana obavještenja mogu čitati sav sadržaj obavještenja, uključujući lične informacije kao što su imena kontakata i poruke. Ova funkcija također može odbaciti obavještenja ili poduzeti radnje vezane za dugmad u obavještenjima, kao što je javljanje na telefonske pozive.\n\nOva funkcija također može uključiti ili isključiti način rada Prioriteti i promijeniti srodne postavke."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Poboljšana obavještenja su zamijenila Prilagodljiva obavještenja Androida u verziji Android 12. Ova funkcija prikazuje predložene radnje i odgovore te organizira vaša obavještenja.\n\nPoboljšana obavještenja mogu pristupiti sadržaju obavještenja, uključujući lične informacije kao što su imena kontakata i poruke. Ova funkcija također može odbacivati obavještenja ili odgovarati na njih, npr. može odgovarati na telefonske pozive i kontrolirati funkciju Ne ometaj."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obavještenje za informacije Rutinskog načina"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Moguće je da će se baterija isprazniti prije uobičajenog punjenja"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Ušteda baterije je aktivirana da bi se produžio vijek trajanja baterije"</string> @@ -2324,4 +2321,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Slika robne marke za aplikaciju"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Provjerite postavke pristupa"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> može pregledati i kontrolirati vaš ekran. Dodirnite da pregledate."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index ecdc94f2a65a..8e0f337193ae 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quart"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foli"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Vertical desconegut"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Horitzontal desconegut"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancel·lada"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualitzat per l\'administrador"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Suprimit per l\'administrador"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"D\'acord"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals i determinades funcions.\n\n"<annotation id="url">"Més informació"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals i determinades funcions."</string> <string name="data_saver_description" msgid="4995164271550590517">"Per reduir l\'ús de dades, la funció Economitzador de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a les dades, però menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Activar l\'Economitzador de dades?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activa"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"El nivell d\'aquesta notificació s\'ha disminuït a Silenci. Toca per proporcionar suggeriments."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Aquesta notificació s\'ha classificat amb un nivell superior. Toca per proporcionar suggeriments."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Aquesta notificació s\'ha classificat amb un nivell inferior. Toca per proporcionar suggeriments."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prova notificacions millorades"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Per continuar rebent accions suggerides, respostes i més, activa les notificacions millorades. Les notificacions adaptatives d\'Android ja no s\'admeten."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activa"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ara no"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificacions millorades"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Ara, les accions i respostes suggerides les proporcionen les notificacions millorades. Les notificacions adaptatives d\'Android ja no s\'admeten."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"D\'acord"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desactiva"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Més informació"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Les notificacions millorades poden llegir tot el contingut de les notificacions, inclosa la informació personal com els noms dels contactes i els missatges. Aquesta funció també pot ignorar les notificacions o fer accions amb els botons de les notificacions, com ara contestar a trucades.\n\nA més, pot activar i desactivar el mode Prioritat i canviar-ne la configuració."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Les notificacions millorades han substituït les notificacions adaptatives d\'Android a Android 12. Aquesta funció mostra les accions i respostes suggerides, i organitza les teves notificacions.\n\nLes notificacions millorades poden accedir al contingut de les notificacions, inclosa la informació personal com els noms dels contactes i els missatges. Aquesta funció també pot ignorar les notificacions o respondre-hi, com ara contestar trucades o controlar el mode No molestis."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificació d\'informació del mode de rutina"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"És possible que la bateria s\'esgoti abans de la càrrega habitual"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"S\'ha activat l\'estalvi de bateria per prolongar-ne la durada"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imatge de brànding de l\'aplicació"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Comprova la configuració d\'accés"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> pot veure i controlar la teva pantalla. Toca per revisar-ho."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index d0494bd9f378..6c1208d56800 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1864,8 +1864,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Neznámý formát na výšku"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Neznámý formát na šířku"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Zrušeno"</string> @@ -1911,10 +1910,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizováno administrátorem"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Smazáno administrátorem"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Spořič baterie zapíná tmavý motiv a omezuje či vypíná aktivitu na pozadí, některé vizuální efekty a některé funkce.\n\n"<annotation id="url">"Další informace"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Spořič baterie zapíná tmavý motiv a omezuje či vypíná aktivitu na pozadí, některé vizuální efekty a některé funkce."</string> <string name="data_saver_description" msgid="4995164271550590517">"Z důvodu snížení využití dat brání spořič dat některým aplikacím v odesílání nebo příjmu dat na pozadí. Aplikace, kterou právě používáte, data přenášet může, ale může tak činit méně často. V důsledku toho se například obrázky nemusejí zobrazit, dokud na ně neklepnete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnout Spořič dat?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnout"</string> @@ -2154,12 +2151,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Toto oznámení bylo ztlumeno. Po klepnutí můžete zadat zpětnou vazbu."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"U tohoto oznámení byla zvýšena priorita. Po klepnutí můžete zadat zpětnou vazbu."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"U tohoto oznámení byla snížena priorita. Po klepnutí můžete zadat zpětnou vazbu."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Vyzkoušejte vylepšená oznámení"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Pokud chcete dál dostávat návrhy akcí, odpovědí a další, zapněte vylepšená oznámení. Adaptivní oznámení systému Android už nejsou podporována."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Zapnout"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Teď ne"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Vylepšená oznámení"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Navrhované akce a odpovědi jsou teď poskytovány prostřednictvím vylepšených oznámení. Adaptivní oznámení systému Android už nejsou podporována."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Vypnout"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Další informace"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Vylepšená oznámení mohou číst veškerý obsah oznámení včetně osobních údajů, jako jsou jména kontaktů a obsah zpráv. Tato funkce také může zavírat oznámení nebo aktivovat tlačítka v oznámeních, například přijímat telefonické hovory.\n\nMůže také zapnout nebo vypnout prioritní režim a změnit související nastavení."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Adaptivní oznámení pro Android byla v systému Android 12 nahrazena vylepšenými oznámeními. Tato funkce ukazuje navrhované akce a odpovědi a uspořádává oznámení.\n\nVylepšená oznámení mají přístup k obsahu oznámení, včetně osobních údajů, jako jsou jména kontaktů a zprávy. Tato funkce také může zavírat oznámení nebo na ně odpovídat, například přijímat telefonní hovory a ovládat režim Nerušit."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informační oznámení režimu sledu činností"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterie se možná vybije před obvyklým časem nabití"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Byl aktivován spořič baterie za účelem prodloužení výdrže"</string> @@ -2358,4 +2355,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Image značky aplikace"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Zkontrolujte nastavení přístupu"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"Tuto obrazovku může zobrazit a ovládat služba <xliff:g id="SERVICE_NAME">%s</xliff:g>. Klepnutím to zkontrolujete."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 39e061d0c5cb..808f0669f6b7 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1708,7 +1708,7 @@ <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Deaktiver genvej"</string> <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="color_correction_feature_name" msgid="3655077237805422597">"Farvekorrigering"</string> <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra dæmpet belysning"</string> <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> @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Ukendt stående format"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Ukendt liggende format"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Annulleret"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Opdateret af din administrator"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet af din administrator"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Batterisparefunktion aktiverer Mørkt tema og begrænser eller deaktiverer aktivitet i baggrunden, nogle visuelle effekter og visse funktioner.\n\n"<annotation id="url">"Få flere oplysninger"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Batterisparefunktion aktiverer Mørkt tema og begrænser eller deaktiverer aktivitet i baggrunden, nogle visuelle effekter og visse funktioner."</string> <string name="data_saver_description" msgid="4995164271550590517">"Datasparefunktionen forhindrer nogle apps i at sende eller modtage data i baggrunden for at reducere dataforbruget. En app, der er i brug, kan få adgang til data, men gør det måske ikke så ofte. Dette kan f.eks. betyde, at billeder ikke vises, før du trykker på dem."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Vil du aktivere Datasparefunktion?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivér"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Denne notifikation blev angivet som Lydløs. Tryk for at give feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Denne notifikation blev placeret højere. Tryk for at give feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Denne notifikation blev placeret lavere. Tryk for at give feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prøv forbedrede notifikationer"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Aktivér forbedrede notifikationer for at fortsætte med at få forslag til handlinger, svar og meget mere. Tilpassede Android-notifikationer understøttes ikke længere."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktivér"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ikke nu"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Forbedrede notifikationer"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Foreslåede handlinger og svar leveres nu via forbedrede notifikationer. Tilpassede Android-notifikationer understøttes ikke længere."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Deaktiver"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Få flere oplysninger"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Forbedrede notifikationer kan læse alt indhold i notifikationer, bl.a. personlige oplysninger som f.eks. beskeder og navne på kontakter. Denne funktion kan også afvise notifikationer eller aktivere knapper i notifikationer, herunder besvare opkald.\n\nDenne funktion kan også aktivere og deaktivere tilstanden Prioritet samt ændre relaterede indstillinger."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Forbedrede notifikationer erstatter automatiske Android-notifikationer i Android 12. Denne funktion viser foreslåede handlinger og svar og organiserer dine notifikationer.\n\nForbedrede notifikationer kan få adgang til indhold i notifikationer, bl.a. personlige oplysninger som f.eks. beskeder og navne på kontakter. Funktionen kan også afvise eller svare på notifikationer, f.eks. besvarelse af telefonopkald og justering af Forstyr ikke."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifikation med oplysninger om rutinetilstand"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Enheden løber muligvis tør for batteri, inden du normalt oplader den"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterisparefunktion er aktiveret for at forlænge batteritiden"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Appens brandimage"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Tjek adgangsindstillingerne"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> kan se og styre din skærm. Tryk for at se mere."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index a92de5aa986e..6a33a0a52f53 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -1520,7 +1520,7 @@ <string name="gpsNotifTicker" msgid="3207361857637620780">"Standortabfrage von <xliff:g id="NAME">%s</xliff:g>"</string> <string name="gpsNotifTitle" msgid="1590033371665669570">"Standortabfrage"</string> <string name="gpsNotifMessage" msgid="7346649122793758032">"Angefordert von <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)"</string> - <string name="gpsVerifYes" msgid="3719843080744112940">"„Ja“"</string> + <string name="gpsVerifYes" msgid="3719843080744112940">"Ja"</string> <string name="gpsVerifNo" msgid="1671201856091564741">"Nein"</string> <string name="sync_too_many_deletes" msgid="6999440774578705300">"Löschbegrenzung überschritten"</string> <string name="sync_too_many_deletes_desc" msgid="7409327940303504440">"Es sind <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> gelöschte Elemente für <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, Konto <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>, vorhanden. Wie möchtest du fortfahren?"</string> @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unbekannt – Hochformat"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unbekannt – Querformat"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Abgebrochen"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Von deinem Administrator aktualisiert"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Von deinem Administrator gelöscht"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Der Energiesparmodus aktiviert das dunkle Design und schränkt Hintergrundaktivitäten, einige optische Effekte und bestimmte Funktionen ein oder deaktiviert sie.\n\n"<annotation id="url">"Weitere Informationen"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Der Energiesparmodus aktiviert das dunkle Design und schränkt Hintergrundaktivitäten, einige optische Effekte und bestimmte Funktionen ein oder deaktiviert sie."</string> <string name="data_saver_description" msgid="4995164271550590517">"Der Datensparmodus verhindert zum einen, dass manche Apps im Hintergrund Daten senden oder empfangen, sodass weniger Daten verbraucht werden. Zum anderen werden die Datenzugriffe der gerade aktiven App eingeschränkt, was z. B. dazu führen kann, dass Bilder erst angetippt werden müssen, bevor sie sichtbar werden."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Datensparmodus aktivieren?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivieren"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Diese Benachrichtigung wurde auf „Lautlos“ herabgestuft. Tippe, um Feedback zu geben."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Diese Benachrichtigung wurde hochgestuft. Tippe, um Feedback zu geben."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Diese Benachrichtigung wurde herabgestuft. Tippe, um Feedback zu geben."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"„Erweiterte Benachrichtigungen“ ausprobieren"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Wenn du weiterhin beispielsweise Vorschläge für Aktionen und Antworten erhalten möchtest, aktiviere die Funktion „Erweiterte Benachrichtigungen“. Adaptive Benachrichtigungen für Android werden nicht mehr unterstützt."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktivieren"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Nicht jetzt"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Erweiterte Benachrichtigungen"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Die Funktion „Erweiterte Benachrichtigungen“ liefert jetzt Vorschläge für Aktionen und Antworten. Adaptive Benachrichtigungen für Android werden nicht mehr unterstützt."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Ausschalten"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Weitere Informationen"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Die Funktion „Erweiterte Benachrichtigungen“ kann alle Benachrichtigungen lesen, darunter auch personenbezogene Daten wie Kontaktnamen und Nachrichten. Außerdem kann sie Benachrichtigungen schließen oder Schaltflächen in Benachrichtigungen verwenden und so beispielsweise Anrufe entgegennehmen.\n\nDiese Funktion kann auch den Prioritätsmodus aktivieren bzw. deaktivieren und zugehörige Einstellungen ändern."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Die Adaptiven Benachrichtigungen wurden in Android 12 durch die Funktion „Erweiterte Benachrichtigungen“ ersetzt. Diese Funktion zeigt Vorschläge für Aktionen und Antworten an und sortiert Benachrichtigungen.\n\nDie Funktion „Erweiterte Benachrichtigungen“ kann alle Benachrichtigungen lesen, darunter auch personenbezogene Daten wie Kontaktnamen und Nachrichten. Außerdem kann sie auf Benachrichtigungen antworten oder diese schließen und so beispielsweise Anrufe entgegennehmen oder „Bitte nicht stören“ steuern."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Infomitteilung zum Ablaufmodus"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Dein Akku könnte vor der gewöhnlichen Ladezeit leer sein"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Energiesparmodus aktiviert, um die Akkulaufzeit zu verlängern"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"App-Branding-Hintergrundbild"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Zugriffseinstellungen prüfen"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> kann deinen Bildschirm sehen und steuern. Zum Prüfen tippen."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 3e0dda79841d..06a358acce14 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"Μ"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Άγνωστος κατακόρυφος προσανατολισμός"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Άγνωστος οριζόντιος προσανατολισμός"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Ακυρώθηκε"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Ενημερώθηκε από τον διαχειριστή σας"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Διαγράφηκε από τον διαχειριστή σας"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα και περιορίζει ή απενεργοποιεί τη δραστηριότητα στο παρασκήνιο, ορισμένα οπτικά εφέ και συγκεκριμένες λειτουργίες.\n\n"<annotation id="url">"Μάθετε περισσότερα"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα και περιορίζει ή απενεργοποιεί τη δραστηριότητα στο παρασκήνιο, ορισμένα οπτικά εφέ και συγκεκριμένες λειτουργίες."</string> <string name="data_saver_description" msgid="4995164271550590517">"Προκειμένου να μειωθεί η χρήση δεδομένων, η Εξοικονόμηση δεδομένων αποτρέπει την αποστολή ή λήψη δεδομένων από ορισμένες εφαρμογές στο παρασκήνιο. Μια εφαρμογή που χρησιμοποιείτε αυτήν τη στιγμή μπορεί να χρησιμοποιήσει δεδομένα αλλά με μικρότερη συχνότητα. Για παράδειγμα, οι εικόνες μπορεί να μην εμφανίζονται μέχρι να τις πατήσετε."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Ενεργ.Εξοικονόμησης δεδομένων;"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Ενεργοποίηση"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Αυτή η ειδοποίηση υποβιβάστηκε στις Αθόρυβες. Πατήστε για να υποβάλετε σχόλια."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Αυτή η ειδοποίηση κατατάχθηκε ψηλότερα. Πατήστε για να υποβάλετε σχόλια."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Αυτή η ειδοποίηση κατατάχθηκε χαμηλότερα. Πατήστε για να υποβάλετε σχόλια."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Δοκιμή βελτιωμ. ειδοποιήσεων"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Για να συνεχίσετε να λαμβάνετε προτεινόμενες ενέργειες, απαντήσεις και άλλα, ενεργοποιήστε τις βελτιωμένες ειδοποιήσεις. Δεν υποστηρίζονται πλέον οι Προσαρμοστικές ειδοποιήσεις Android."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Ενεργοποίηση"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Όχι τώρα"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Βελτιωμένες ειδοποιήσεις"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Οι προτεινόμενες ενέργειες και απαντήσεις παρέχονται πλέον από βελτιωμένες ειδοποιήσεις. Δεν υποστηρίζονται πλέον οι Προσαρμοστικές ειδοποιήσεις Android."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ΟΚ"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Απενεργοποίηση"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Μάθετε περισσότερα"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Οι Βελτιωμένες ειδοποιήσεις έχουν τη δυνατότητα ανάγνωσης όλου του περιεχομένου ειδοποιήσεων, συμπεριλαμβανομένων των προσωπικών πληροφοριών, όπως ονομάτων επαφών και μηνυμάτων. Αυτή η λειτουργία έχει επίσης τη δυνατότητα παράβλεψης ειδοποιήσεων ή λήψης ενεργειών σε κουμπιά στις ειδοποιήσεις, όπως η απάντηση τηλεφωνικών κλήσεων.\n\nΕπίσης, έχει τη δυνατότητα ενεργοποίησης ή απενεργοποίησης της λειτουργίας Προτεραιότητας, καθώς και αλλαγής των σχετικών ρυθμίσεων."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Στο Android 12, οι Βελτιωμένες ειδοποιήσεις αντικατέστησαν τις Προσαρμοστικές ειδοποιήσεις Android. Αυτή η λειτουργία εμφανίζει προτεινόμενες ενέργειες και απαντήσεις και οργανώνει τις ειδοποιήσεις σας.\n\nΟι Βελτιωμένες ειδοποιήσεις μπορούν να αποκτήσουν πρόσβαση σε περιεχόμενο ειδοποιήσεων, συμπεριλαμβανομένων προσωπικών στοιχείων, όπως ονομάτων επαφών και μηνυμάτων. Αυτή η λειτουργία παρέχει επίσης τη δυνατότητα παράβλεψης ή απάντησης ειδοποιήσεων, όπως η απάντηση σε τηλεφωνικές κλήσεις και ο έλεγχος της λειτουργίας Μην ενοχλείτε."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ειδοποίηση πληροφοριών λειτουργίας Ρουτίνας"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Η μπαταρία μπορεί να εξαντληθεί πριν από τη συνηθισμένη φόρτιση"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Η Εξοικονόμηση μπαταρίας ενεργοποιήθηκε για την επέκταση της διάρκειας ζωής της μπαταρίας"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Εικόνα επωνυμίας εφαρμογής"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Ελέγξτε τις ρυθμίσεις προσβασιμότητας"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"Η υπηρεσία <xliff:g id="SERVICE_NAME">%s</xliff:g> μπορεί να βλέπει και να ελέγχει την οθόνη σας. Πατήστε για έλεγχο."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index bb7b1fac0d21..809375274f95 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelled"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features.\n\n"<annotation id="url">"Learn more"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features."</string> <string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you\'re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"This notification was demoted to silent. Tap to provide feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"This notification was ranked higher. Tap to provide feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"This notification was ranked lower. Tap to provide feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Try enhanced notifications"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"To keep getting suggested actions, replies and more, turn on enhanced notifications. Android Adaptive Notifications are no longer supported."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Turn on"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Not now"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Enhanced notifications"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Suggested actions and replies are now provided by enhanced notifications. Android adaptive notifications are no longer supported."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Enhanced notifications can read all notification content, including personal information like contact names and messages. This feature can also dismiss notifications or take actions on buttons in notifications, such as answering phone calls.\n\nThis feature can also turn Priority mode on or off and change related settings."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls and controlling Do Not Disturb."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Check access settings"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> can view and control your screen. Tap to review."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 4af88dbad44c..96dd0dee89bd 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelled"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features.\n\n"<annotation id="url">"Learn more"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features."</string> <string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you\'re currently using can access data, but may do so less frequently. This may mean, for example, that images don\'t display until you tap them."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"This notification was demoted to silent. Tap to provide feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"This notification was ranked higher. Tap to provide feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"This notification was ranked lower. Tap to provide feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Try enhanced notifications"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"To keep getting suggested actions, replies and more, turn on enhanced notifications. Android Adaptive Notifications are no longer supported."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Turn on"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Not now"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Enhanced notifications"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Suggested actions and replies are now provided by enhanced notifications. Android adaptive notifications are no longer supported."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Enhanced notifications can read all notification content, including personal information like contact names and messages. This feature can also dismiss notifications or take actions on buttons in notifications, such as answering phone calls.\n\nThis feature can also turn Priority mode on or off and change related settings."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls and controlling Do Not Disturb."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Check access settings"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> can view and control your screen. Tap to review."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index f322d0583c28..3dc2d7ddc26d 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelled"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features.\n\n"<annotation id="url">"Learn more"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features."</string> <string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"This notification was demoted to silent. Tap to provide feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"This notification was ranked higher. Tap to provide feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"This notification was ranked lower. Tap to provide feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Try enhanced notifications"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"To keep getting suggested actions, replies and more, turn on enhanced notifications. Android Adaptive Notifications are no longer supported."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Turn on"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Not now"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Enhanced notifications"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Suggested actions and replies are now provided by enhanced notifications. Android adaptive notifications are no longer supported."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Enhanced notifications can read all notification content, including personal information like contact names and messages. This feature can also dismiss notifications or take actions on buttons in notifications, such as answering phone calls.\n\nThis feature can also turn Priority mode on or off and change related settings."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls and controlling Do Not Disturb."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Check access settings"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> can view and control your screen. Tap to review."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 1eb402da80dd..789a654b5d80 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelled"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features.\n\n"<annotation id="url">"Learn more"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects and certain features."</string> <string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"This notification was demoted to silent. Tap to provide feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"This notification was ranked higher. Tap to provide feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"This notification was ranked lower. Tap to provide feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Try enhanced notifications"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"To keep getting suggested actions, replies and more, turn on enhanced notifications. Android Adaptive Notifications are no longer supported."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Turn on"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Not now"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Enhanced notifications"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Suggested actions and replies are now provided by enhanced notifications. Android adaptive notifications are no longer supported."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Enhanced notifications can read all notification content, including personal information like contact names and messages. This feature can also dismiss notifications or take actions on buttons in notifications, such as answering phone calls.\n\nThis feature can also turn Priority mode on or off and change related settings."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls and controlling Do Not Disturb."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Check access settings"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> can view and control your screen. Tap to review."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 65b00c812826..43c951e22e5b 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelled"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, and certain features.\n\n"<annotation id="url">"Learn more"</annotation>""</string> + <string name="battery_saver_description" msgid="5693741424234005958">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, and certain features."</string> <string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"This notification was demoted to Silent. Tap to provide feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"This notification was ranked higher. Tap to provide feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"This notification was ranked lower. Tap to provide feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Try enhanced notifications"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"To keep getting suggested actions, replies, and more, turn on enhanced notifications. Android Adaptive Notifications are no longer supported."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Turn on"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Not now"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Enhanced notifications"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Suggested actions and replies are now provided by enhanced notifications. Android Adaptive Notifications are no longer supported."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Enhanced notifications can read all notification content, including personal information like contact names and messages. This feature can also dismiss notifications or take actions on buttons in notifications, such as answering phone calls.\n\nThis feature can also turn Priority mode on or off and change related settings."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Enhanced notifications replaced Android Adaptive Notifications in Android 12. This feature shows suggested actions and replies, and organizes your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls and controlling Do Not Disturb."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string> @@ -2290,4 +2287,6 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Check access settings"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> can view and control your screen. Tap to review."</string> + <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"<xliff:g id="MESSAGE">%1$s</xliff:g> Translated."</string> + <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"Message translated from <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> to <xliff:g id="TO_LANGUAGE">%2$s</xliff:g>."</string> </resources> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index b3612404cf86..c1821906d27d 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Cualquier tamaño vertical"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Cualquier tamaño horizontal"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelada"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Tu administrador actualizó este paquete"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Tu administrador borró este paquete"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"El Ahorro de batería activa el Tema oscuro y desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones determinadas.\n\n"<annotation id="url">"Más información"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"El Ahorro de batería activa el Tema oscuro y desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones determinadas."</string> <string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, el modo Ahorro de datos evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"¿Deseas activar Ahorro de datos?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Esta notificación descendió de a Silenciada. Presiona para enviar comentarios."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificación recibió una clasificación superior. Presiona para enviar comentarios."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificación recibió una clasificación inferior. Presiona para enviar comentarios."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prueba las notif. mejoradas"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Activa las notificaciones mejoradas para seguir recibiendo acciones sugeridas, respuestas y mucho más. Ya no se admiten las notificaciones adaptables de Android."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activar"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ahora no"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificaciones mejoradas"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Las notificaciones mejoradas ahora brindan respuestas y acciones sugeridas. Ya no se admiten las notificaciones adaptables de Android."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Aceptar"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desactivar"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Más información"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Las notificaciones mejoradas pueden leer todo el contenido de notificaciones, incluido el que contenga información personal, como nombres de contactos y mensajes. Esta función también podrá descartar notificaciones o realizar acciones en botones de notificaciones, como responder llamadas.\n\nTambién puede activar o desactivar el Modo prioridad y cambiar la configuración relacionada."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Las notificaciones mejoradas reemplazaron a las notificaciones adaptables en Android 12. Esta función muestra respuestas y acciones sugeridas, y organiza tus notificaciones.\n\nLas notificaciones mejoradas pueden acceder a todo el contenido de notificaciones, lo que incluye información personal, como nombres de contactos y mensajes. También puede descartar o responder notificaciones, como responder llamadas y controlar la función No interrumpir."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación de información del modo de Rutinas"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Es posible que la batería se agote antes de la carga habitual"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Se activó el Ahorro de batería para extender la duración de la batería"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imagen de marca de la aplicación"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Verifica la configuración de acceso"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> puede ver y controlar tu pantalla. Presiona para revisar esta opción."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 13ed8ffbcafe..1e880e46d570 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Cualquier tamaño vertical"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Cualquier tamaño horizontal"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelado"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado por el administrador"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado por el administrador"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales y ciertas funciones.\n\n"<annotation id="url">"Más información"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales y ciertas funciones."</string> <string name="data_saver_description" msgid="4995164271550590517">"Ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que puede reducir el uso de datos. Una aplicación que estés usando de forma activa puede acceder a los datos, aunque con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"¿Activar Ahorro de datos?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"La importancia de esta notificación ha disminuido a Silencio. Toca para enviar comentarios."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificación aparecerá en una posición más alta. Toca para enviar comentarios."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificación aparecerá en una posición más baja. Toca para enviar comentarios."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probar notificaciones mejoradas"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para seguir recibiendo sugerencias de acciones, respuestas y más, activa las notificaciones mejoradas. Las notificaciones adaptativas de Android ya no están disponibles."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activar"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ahora no"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificaciones mejoradas"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Ahora se sugieren acciones y respuestas mediante notificaciones mejoradas. Ya no se admiten las notificaciones adaptativas de Android."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Aceptar"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desactivar"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Más información"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Las notificaciones mejoradas pueden leer todo el contenido de las notificaciones, incluidas las relacionadas con información personal, como nombres y mensajes de tus contactos. Esta función también puede cerrar notificaciones o utilizar los botones de las notificaciones, por ejemplo, para responder llamadas telefónicas.\n\nAdemás, puede activar o desactivar el modo Prioridad y cambiar ajustes relacionados con él."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Las notificaciones mejoradas sustituyen a las notificaciones adaptativas en Android 12. Esta nueva función te sugiere acciones y respuestas, y organiza tus notificaciones.\n\nLa función puede acceder al contenido de tus notificaciones, incluida información personal, como nombres de contactos y mensajes. También puede cerrar o responder a notificaciones; por ejemplo, puede descolgar llamadas telefónicas y controlar No molestar."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación sobre el modo rutina"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Quizás se agote la batería antes de lo habitual"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Se ha activado el modo Ahorro de batería para aumentar la duración de la batería"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imagen de marca de aplicación"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Comprueba los ajustes de acceso"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> puede ver y controlar tu pantalla. Toca para revisarlo."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 9d63c3d14af0..865e9d0d6774 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Tundmatu vertikaalpaigutuses"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Tundmatu horisontaalpaigutuses"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Tühistatud"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Administraator on seda värskendanud"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administraator on selle kustutanud"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Akusäästja lülitab sisse tumeda teema ja lülitab välja taustategevused, mõned visuaalsed efektid ja teatud funktsioonid või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Akusäästja lülitab sisse tumeda teema ja lülitab välja taustategevused, mõned visuaalsed efektid ja teatud funktsioonid või piirab neid."</string> <string name="data_saver_description" msgid="4995164271550590517">"Andmekasutuse vähendamiseks keelab andmemahu säästja mõne rakenduse puhul andmete taustal saatmise ja vastuvõtmise. Rakendus, mida praegu kasutate, pääseb andmesidele juurde, kuid võib seda teha väiksema sagedusega. Seetõttu võidakse näiteks pildid kuvada alles siis, kui neid puudutate."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Lülitada andmemahu säästja sisse?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Lülita sisse"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Sellele märguandele määrati prioriteet Vaikne. Puudutage tagasiside andmiseks."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Sellele märguandele määrati kõrgem prioriteet. Puudutage tagasiside andmiseks."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Sellele märguandele määrati madalam prioriteet. Puudutage tagasiside andmiseks."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Proovige täiustatud märguandeid"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Soovitatud toimingute, vastuste ja muu nägemiseks ka edaspidi lülitage sisse täiustatud märguanded. Androidi kohanduvaid märguandeid enam ei toetata."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Lülita sisse"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Mitte praegu"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Täiustatud märguanded"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Soovitatud toiminguid ja vastuseid pakuvad nüüd täiustatud märguanded. Androidi kohanduvaid märguandeid enam ei toetata."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Lülita välja"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Lisateave"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Täiustatud märguanded saavad lugeda kogu märguande sisu, sh isiklikku teavet, nagu kontaktide nimed ja sõnumid. Samuti saab selle funktsiooniga märguannetest loobuda või märguannetes nuppude abil toiminguid teha (nt vastata telefonikõnedele).\n\nLisaks saab selle funktsiooniga sisse või välja lülitada režiimi Prioriteetne ja muuta seotud seadeid."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Androidi versioonis 12 asendasid täiustatud märguanded Androidi kohanduvad märguanded. See funktsioon näitab soovitatud toiminguid ja vastuseid ning korrastab teie märguandeid.\n\nTäiustatud märguanded pääsevad juurde märguande sisule, sh isiklikule teabele, nagu kontaktide nimed ja sõnumid. Samuti saab selle funktsiooni abil märguannetest loobuda või neile vastata (nt vastata telefonikõnedele ja juhtida funktsiooni Mitte segada)."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutiinirežiimi teabe märguanne"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Aku võib enne tavapärast laadimist tühjaks saada"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Akusäästja aktiveeriti aku tööea pikendamiseks"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Rakenduse brändi kujutis"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Kontrollige juurdepääsuseadeid"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> saab vaadata ja hallata teie ekraanikuva. Puudutage ülevaatamiseks."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index a8a5d1f514a4..e0af24f9f97c 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch (AEB)"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto (AEB)"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap (AEB)"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K (Txina)"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K (Txina)"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1 (Txina)"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu (Japonia)"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2 (Japonia)"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4 (Japonia)"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Bertikal ezezaguna"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Horizontal ezezaguna"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Bertan behera utzi da"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Administratzaileak eguneratu du"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratzaileak ezabatu du"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Ados"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Bateria-aurrezleak gai iluna aktibatzen du, eta murriztu edo desaktibatu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta eginbide jakin batzuk.\n\n"<annotation id="url">"Lortu informazio gehiago"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Bateria-aurrezleak gai iluna aktibatzen du, eta murriztu edo desaktibatu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta eginbide jakin batzuk."</string> <string name="data_saver_description" msgid="4995164271550590517">"Datuen erabilera murrizteko, atzeko planoan datuak bidaltzea eta jasotzea galarazten die datu-aurrezleak aplikazio batzuei. Une honetan erabiltzen ari zaren aplikazio batek datuak atzitu ahal izango ditu, baina baliteke maiztasun txikiagoarekin atzitzea. Horrela, adibidez, baliteke irudiak ez erakustea haiek sakatu arte."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Datu-aurrezlea aktibatu nahi duzu?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Aktibatu"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Isilarazi da jakinarazpena. Sakatu hau oharrak bidaltzeko."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Mailaz igo da jakinarazpena. Sakatu hau oharrak bidaltzeko."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Mailaz jaitsi da jakinarazpena. Sakatu hau oharrak bidaltzeko."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probatu jakinarazpen hobetuak"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Iradokitako ekintzak, erantzunak eta abar jasotzen jarraitzeko, aktibatu jakinarazpen hobetuak. Android-en jakinarazpen egokituak ez dira onartzen jada."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktibatu"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Orain ez"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Jakinarazpen hobetuak"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Orain, jakinarazpen hobetuen bitartez iradokitzen dira ekintzak eta erantzunak. Android-eko jakinarazpen egokituak ez dira onartzen jada."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Ados"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desaktibatu"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Lortu informazio gehiago"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Jakinarazpen hobetuek jakinarazpenen eduki osoa irakur dezakete, informazio pertsonala barne (esaterako, kontaktuen izenak eta mezuak). Halaber, jakinarazpenak baztertu edo jakinarazpenetako botoiak erabil ditzake eginbideak; adibidez, telefono-deiak erantzun.\n\nHorretaz gain, lehentasunezko modua aktibatu edo desaktiba dezake, eta erlazionatutako ezarpenak aldatu."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12n, jakinarazpen hobetuek ordeztu dituzte Android-eko jakinarazpen egokituak. Eginbide horrek, iradokitako ekintzak eta erantzunak erakutsi, eta zure jakinarazpenak antolatzen ditu.\n\nJakinarazpen hobetuek jakinarazpenen eduki osoa atzi dezakete, informazio pertsonala barne (esaterako, kontaktuen izenak eta mezuak). Halaber, jakinarazpenak baztertu edo haiei erantzun diezaieke eginbideak; adibidez, telefono-deiak erantzun eta ez molestatzeko modua kontrolatu."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ohitura moduaren informazio-jakinarazpena"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baliteke bateria ohi baino lehenago agortzea"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Bateria-aurrezlea aktibatuta dago bateriaren iraupena luzatzeko"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Aplikazioaren marka-irudia"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Egiaztatu sarbide-ezarpenak"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> zerbitzuak pantaila ikusi eta kontrola dezake. Sakatu berrikusteko."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index dc0b0155e77a..03a962b5f322 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -542,10 +542,10 @@ <string name="permdesc_bluetooth_advertise" product="default" msgid="6085174451034210183">"برنامه مجاز میشود در دستگاههای بلوتوث اطراف تبلیغ کند."</string> <string name="permlab_uwb_ranging" msgid="8141915781475770665">"مشخص کردن موقعیت نسبی بین دستگاههای باند فوقوسیع اطراف"</string> <string name="permdesc_uwb_ranging" msgid="2519723069604307055">"به برنامه اجازه داده میشود موقعیت نسبی بین دستگاههای باند فوقوسیع اطراف را مشخص کند"</string> - <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"اطلاعات ترجیحی سرویس پولی «ارتباط میدان نزدیک» (NFC)"</string> - <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"به برنامه اجازه میدهد اطلاعات ترجیحی سرویس پولی «ارتباط میدان نزدیک» (NFC)، مانند کمکهای ثبتشده و مقصد مسیر را دریافت کند."</string> + <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"اطلاعات ترجیحی سرویس پولی NFC"</string> + <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"به برنامه اجازه میدهد اطلاعات ترجیحی سرویس پولی NFC، مانند کمکهای ثبتشده و مقصد مسیر را دریافت کند."</string> <string name="permlab_nfc" msgid="1904455246837674977">"کنترل ارتباط راه نزدیک"</string> - <string name="permdesc_nfc" msgid="8352737680695296741">"به برنامه اجازه میدهد تا با تگهای «ارتباط میدان نزدیک» (NFC)، کارتها و فایلخوان ارتباط برقرار کند."</string> + <string name="permdesc_nfc" msgid="8352737680695296741">"به برنامه اجازه میدهد تا با تگهای NFC، کارتها و فایلخوان ارتباط برقرار کند."</string> <string name="permlab_disableKeyguard" msgid="3605253559020928505">"غیرفعال کردن قفل صفحه شما"</string> <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"به برنامه امکان میدهد قفل کلید و هر گونه امنیت گذرواژه مرتبط را غیرفعال کند. بهعنوان مثال تلفن هنگام دریافت یک تماس تلفنی ورودی قفل کلید را غیرفعال میکند و بعد از پایان تماس، قفل کلید را دوباره فعال میکند."</string> <string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"درخواست پیچیدگی قفل صفحه"</string> @@ -712,7 +712,7 @@ <string name="permlab_removeDrmCertificates" msgid="710576248717404416">"حذف گواهیهای DRM"</string> <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"به برنامه امکان میدهد گواهیهای DRM را حذف کند. نباید برای برنامههای عادی هیچوقت لازم باشد."</string> <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"مقید به سرویس پیامرسانی شرکت مخابراتی"</string> - <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"به کنترلکننده اجازه میدهد که به سطح بالای رابط کاربر سرویس پیامرسانی شرکت مخابراتی مقید شود. هرگز نباید برای برنامههای عادی مورد نیاز شود."</string> + <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"به کنترلکننده اجازه میدهد که به سطح بالای میانای کاربر سرویس پیامرسانی شرکت مخابراتی مقید شود. هرگز نباید برای برنامههای عادی مورد نیاز شود."</string> <string name="permlab_bindCarrierServices" msgid="2395596978626237474">"اتصال به سرویسهای شرکت مخابراتی"</string> <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"به دارنده امکان میدهد به سرویسهای شرکت مخابراتی متصل شود. هرگز نباید برای برنامههای عادی مورد نیاز باشد."</string> <string name="permlab_access_notification_policy" msgid="5524112842876975537">"دسترسی به حالت «مزاحم نشوید»"</string> @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"بزرگ"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"عمودی نامشخص"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"افقی نامشخص"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"لغو شد"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"توسط سرپرست سیستم بهروزرسانی شد"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"توسط سرپرست سیستم حذف شد"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"تأیید"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"«بهینهسازی باتری» «طرح زمینه تیره» را روشن میکند و فعالیت پسزمینه، برخی از جلوههای بصری، و ویژگیهایی خاص را محدود یا خاموش میکند.\n\n"<annotation id="url">"بیشتر بدانید"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"«بهینهسازی باتری» «طرح زمینه تیره» را روشن میکند و فعالیت پسزمینه، برخی از جلوههای بصری، و ویژگیهایی خاص را محدود یا خاموش میکند."</string> <string name="data_saver_description" msgid="4995164271550590517">"برای کمک به کاهش مصرف داده، «صرفهجویی داده» از ارسال و دریافت داده در پسزمینه در بعضی برنامهها جلوگیری میکند. برنامهای که درحالحاضر استفاده میکنید میتواند به دادهها دسترسی داشته باشد اما دفعات دسترسی آن محدود است. این میتواند به این معنی باشد که، برای مثال، تصاویر تازمانیکه روی آنها ضربه نزنید نشان داده نمیشوند."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"«صرفهجویی داده» روشن شود؟"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"روشن کردن"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"این اعلان به «بیصدا» تنزل داده شد. برای ارائه بازخورد، ضربه بزنید."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"این اعلان در رتبه بالاتری قرار گرفت. برای ارائه بازخورد، ضربه بزنید."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"این اعلان در رتبه پایینتری قرار گرفت. برای ارائه بازخورد، ضربه بزنید."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"امتحان کردن اعلانهای بهبودیافته"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"برای اینکه پاسخها و کنشهای پیشنهادی و موارد دیگر را همچنان دریافت کنید، اعلانهای بهبودیافته را روشن کنید. از «اعلانهای تطبیقی Android» دیگر پشتیبانی نمیشود."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"روشن کردن"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"الآن نه"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"اعلانهای بهبودیافته"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"اکنون پاسخها و کنشهای پیشنهادی ازطریق اعلانهای بهبودیافته ارائه میشوند. «اعلانهای تطبیقی Android» دیگر پشتیبانی نمیشوند."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"تأیید"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"خاموش کردن"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"بیشتر بدانید"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"اعلانهای بهبودیافته میتواند محتوای همه اعلانها، ازجمله اطلاعات شخصی مثل نام مخاطبین و پیامها را بخواند. این ویژگی همچنین میتواند اعلانها را ببندد یا بااستفاده از دکمههای موجود در اعلانها اقداماتی انجام دهد، مثلاً به تماسهای تلفنی پاسخ دهد.\n\nبهعلاوه، این ویژگی میتواند «حالت اولویت» را روشن یا خاموش کند و تنظیمات مربوطه را تغییر دهد."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"در Android نسخه ۱۲، اعلانهای بهبودیافته جایگزین «اعلانهای تطبیقی» شده است. این ویژگی پاسخها و کنشهای پیشنهادی را نمایش میدهد و اعلانهایتان را سازماندهی میکند.\n\nاعلانهای بهبودیافته میتوانند به محتوای اعلان، ازجمله اطلاعات شخصی مثل نامها و پیامهای مخاطبین دسترسی داشته باشند. این ویژگی همچنین میتواند اعلانها را رد کند یا به آنها پاسخ دهد؛ مثلاً پاسخ به تماسهای تلفنی و کنترل کردن «مزاحم نشوید»."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"اعلان اطلاعات حالت روال معمول"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ممکن است شارژ باتری قبل از شارژ معمول تمام شود"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"جهت افزایش عمر باتری، «بهینهسازی باتری» فعال شد"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"تصویر نمانامسازی برنامه"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"بررسی تنظیمات دسترسی"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> میتواند صفحهنمایش شما را مشاهده و کنترل کند. برای مرور، ضربه بزنید."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 310ce66dc7b3..bcc6d88fd882 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch (184 mm x 267 mm)"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto (203 mm x 254 mm)"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap (203 mm x 330 mm)"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K (270 mm x 390 mm)"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K (195 mm x 270 mm)"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1 (102 mm x 165 mm)"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu (240 mm x 322,1 mm)"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2 (240 mm x 332 mm)"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4 (105 mm x 235 mm)"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Tuntematon pystykoko"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Tuntematon vaakakoko"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Peruutettu"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Järjestelmänvalvoja päivitti tämän."</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Järjestelmänvalvoja poisti tämän."</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Virransäästö laittaa tumman teeman päälle ja laittaa pois päältä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja tiettyjä muita ominaisuuksia.\n\n"<annotation id="url">"Lue lisää"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Virransäästö laittaa tumman teeman päälle ja laittaa pois päältä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja tiettyjä muita ominaisuuksia."</string> <string name="data_saver_description" msgid="4995164271550590517">"Data Saver estää joitakin sovelluksia lähettämästä tai vastaanottamasta tietoja taustalla, jotta datan käyttöä voidaan vähentää. Käytössäsi oleva sovellus voi yhä käyttää dataa, mutta se saattaa tehdä niin tavallista harvemmin. Tämä voi tarkoittaa esimerkiksi sitä, että kuva ladataan vasta, kun kosketat sitä."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Otetaanko Data Saver käyttöön?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Ota käyttöön"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Tämä ilmoitus hiljennettiin. Lähetä palautetta napauttamalla."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Tämän ilmoituksen tasoa nostettiin. Lähetä palautetta napauttamalla."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Tämän ilmoituksen tasoa laskettiin. Lähetä palautetta napauttamalla."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Kokeile parann. ilmoituksia"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Jos haluat jatkossakin saada ehdotuksia toiminnoista, vastauksista ja muista, laita parannetut ilmoitukset päälle. Androidin mukautuvia ilmoituksia ei enää tueta."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Laita päälle"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ei nyt"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Parannetut ilmoitukset"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Parannetut ehdotukset tarjoavat nyt toiminto- ja vastausehdotuksia. Androidin mukautuvia ilmoituksia ei enää tueta."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Laita pois päältä"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Lue lisää"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Parannetut ilmoitukset voivat lukea kaikkea ilmoitussisältöä, myös henkilökohtaisia tietoja (esim. kontaktien nimet ja viestit). Ominaisuus voi myös ohittaa ilmoituksia tai käyttää niiden toimintopainikkeita, esim. vastata puheluihin.\n\nLisäksi ominaisuus voi laittaa Tärkeät-tilan päälle tai pois päältä ja muuttaa siihen liittyviä asetuksia."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Parannetut ilmoitukset korvasivat Androidin mukautuvat ilmoitukset Android 12:ssa. Tämä ominaisuus näyttää toiminto- ja vastausehdotuksia ja järjestää ilmoituksesi.\n\nParannetuilla ilmoituksilla on pääsy kaikkeen ilmoitussisältöön, myös henkilökohtaisiin tietoihin (esim. kontaktien nimet ja viestit). Tämä ominaisuus voi myös ohittaa ilmoituksia tai vastata niihin, esim. vastata puheluihin ja ohjata Älä häiritse ‑tilaa."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ohjelmatilan tietoilmoitus"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akku saattaa loppua ennen normaalia latausaikaa"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Virransäästö otettu käyttöön akunkeston pidentämiseksi"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Sovelluksen tuotemerkkikuva"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Tarkista pääsyasetukset"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> voi nähdä ja ohjata näyttöäsi. Tarkista napauttamalla."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index cb5e61645999..178ca39284f1 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarque"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"In-quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Taille inconnue au format portrait"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Taille inconnue au format paysage"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Annulé"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Mise à jour par votre administrateur"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"La fonctionnalité Économiseur de pile active le thème sombre et limite ou désactive l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités.\n\n"<annotation id="url">"En savoir plus"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"La fonctionnalité Économiseur de pile active le thème sombre et limite ou désactive l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités."</string> <string name="data_saver_description" msgid="4995164271550590517">"Pour aider à diminuer l\'utilisation des données, la fonctionnalité Économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Une application que vous utilisez actuellement peut accéder à des données, mais peut le faire moins souvent. Cela peut signifier, par exemple, que les images ne s\'affichent pas jusqu\'à ce que vous les touchiez."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Cette notification a été rétrogradée à Silencieuse. Touchez pour envoyer des commentaires."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Cette notification a été élevée d\'un niveau. Touchez pour envoyer des commentaires."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Cette notification a été abaissée d\'un niveau. Touchez pour envoyer des commentaires."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Essayer les notif. améliorées"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Pour continuer de recevoir des suggestions d\'actions, de réponses et plus encore, activez les notifications améliorées. Les notifications adaptatives Android ne sont plus prises en charge."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activer"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Plus tard"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notifications améliorées"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Les suggestions d\'actions et de réponses sont maintenant fournies par les notifications améliorées. Les notifications adaptatives Android ne sont plus prises en charge."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Désactiver"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"En savoir plus"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Les notifications améliorées peuvent lire le contenu de toutes les notifications, y compris les renseignements personnels comme le nom des contacts et les messages. Cette fonctionnalité peut aussi fermer des notifications ou effectuer des actions sur les boutons dans les notifications, comme répondre aux appels entrants.\n\nElle peut aussi activer et désactiver le mode Prioritaire et modifier les paramètres connexes."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Les notifications améliorées ont remplacé les notifications adaptatives Android sous Android 12. Cette fonctionnalité vous présente des suggestions d\'actions et de réponse, et organise vos notifications.\n\nLes notifications améliorées peuvent accéder au contenu de toutes les notifications, y compris les renseignements personnels comme le nom des contacts et les messages. Cette fonctionnalité peut aussi fermer des notifications ou interagir avec elles, comme répondre aux appels téléphoniques et gérer le mode Ne pas déranger."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification d\'information du mode Routine"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"La pile pourrait s\'épuiser avant la charge habituelle"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Le mode Économiseur de pile est activé afin de prolonger l\'autonomie"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Image de marque de l\'application"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Vérifiez les paramètres d\'accès"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> peut voir et contrôler votre écran. Touchez pour examiner."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index d68d00d29eb2..d4e8d57aa30e 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Taille inconnue au format portrait"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Taille inconnue au format paysage"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Tâche annulée."</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Mis à jour par votre administrateur"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"L\'économiseur de batterie active le thème sombre et limite ou désactive les activités en arrière-plan et certains effets visuels et fonctionnalités.\n\n"<annotation id="url">"En savoir plus"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"L\'économiseur de batterie active le thème sombre et limite ou désactive les activités en arrière-plan et certains effets visuels et fonctionnalités."</string> <string name="data_saver_description" msgid="4995164271550590517">"Pour réduire la consommation des données, l\'Économiseur de données empêche certaines applis d\'envoyer ou de recevoir des données en arrière-plan. Les applis que vous utiliserez pourront toujours accéder aux données, mais le feront moins fréquemment. Par exemple, les images pourront ne pas s\'afficher tant que vous n\'aurez pas appuyé pas dessus."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données ?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Cette notification a été abaissée à la catégorie \"Silencieux\". Appuyez ici pour donner votre avis."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Cette notification a été élevée d\'un niveau. Appuyez ici pour donner votre avis."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Cette notification a été abaissée d\'un niveau. Appuyez ici pour donner votre avis."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Testez les notifications améliorées"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Activez les notifications améliorées pour continuer à recevoir des suggestions d\'actions, de réponses et plus encore. Les notifications intelligentes Android ne sont plus disponibles."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activer"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Pas maintenant"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notifications améliorées"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Les actions et réponses suggérées sont maintenant fournies via les notifications améliorées. Les notifications intelligentes Android ne sont plus disponibles."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Désactiver"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"En savoir plus"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Les notifications améliorées peuvent lire tout le contenu des notifications, y compris des informations personnelles comme le nom des contacts et les messages. Cette fonctionnalité peut aussi fermer des notifications ou effectuer des actions grâce aux boutons figurant dans ces notifications, par exemple répondre aux appels téléphoniques.\n\nElle peut aussi activer ou désactiver le mode Prioritaire et modifier les paramètres associés."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Les notifications améliorées remplacent les notifications intelligentes dans Android 12. Cette fonctionnalité affiche les actions et réponses suggérées, et organise vos notifications.\n\nElle a accès au contenu des notifications, y compris aux informations personnelles comme le nom des contacts et les messages. Elle peut aussi fermer les notifications ou effectuer des actions, comme répondre à un appel téléphonique et contrôler le mode Ne pas déranger."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification d\'information du mode Routine"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Vous risquez d\'être à court de batterie plus tôt que prévu"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Économiseur de batterie activé pour prolonger l\'autonomie"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Image de branding de l\'application"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Vérifiez les paramètres d\'accès"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> peut afficher et contrôler votre écran. Appuyez ici pour en savoir plus."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 9c089228f719..1b8a51185f08 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Tamaño folio"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Retrato descoñecido"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Paisaxe descoñecida"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelada"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado polo teu administrador"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado polo teu administrador"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Coa función Aforro de batería actívase o tema escuro e restrínxense ou desactívanse a actividade en segundo plano, algúns efectos visuais e determinadas funcións.\n\n"<annotation id="url">"Máis información"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Coa función Aforro de batería actívase o tema escuro e restrínxense ou desactívanse a actividade en segundo plano, algúns efectos visuais e determinadas funcións."</string> <string name="data_saver_description" msgid="4995164271550590517">"Para contribuír a reducir o uso de datos, o aforro de datos impide que algunhas aplicacións envíen ou reciban datos en segundo plano. Cando esteas utilizando unha aplicación, esta poderá acceder aos datos, pero é posible que o faga con menos frecuencia. Por exemplo, poida que as imaxes non se mostren ata que as toques."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Queres activar o aforro de datos?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"O nivel desta notificación diminuíu a Silenciosa. Toca para compartir a túa opinión."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificación clasificouse nun nivel superior. Toca para compartir a túa opinión."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificación clasificouse nun nivel inferior. Toca para compartir a túa opinión."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Proba notificacións melloradas"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para seguir recibindo accións suxeridas, respostas e moito máis, activa as notificacións melloradas. As notificacións intelixentes de Android xa non son compatibles."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activar"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Agora non"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificacións melloradas"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Agora, as notificacións melloradas son as que che ofrecen suxestións de accións e respostas. As notificacións intelixentes de Android xa non son compatibles."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Aceptar"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desactivar"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Máis información"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Coas notificacións melloradas pódese ler todo o contido das notificacións, mesmo a información persoal (por exemplo, os nomes dos contactos e as mensaxes). Con esta función tamén se poden ignorar as notificacións ou realizar accións nos botóns que aparecen nelas, como responder chamadas telefónicas.\n\nAdemais, permite activar e desactivar o modo de prioridade e cambiar a configuración relacionada."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"En Android 12, as notificacións melloradas substitúen as notificacións intelixentes. Esta función ofréceche suxestións de accións e respostas, ademais de organizar as notificacións.\n\nEste servizo pode acceder ao contido das notificacións, mesmo á información persoal, como os nomes dos contactos e as mensaxes. Ademais, esta función pode ignorar ou responder as notificacións (por exemplo, coller chamadas telefónicas e controlar o modo Non molestar)."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación da información do modo de rutina"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"A batería pode esgotarse antes do habitual"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Para ampliar a duración da batería activouse a función Aforro de batería"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imaxe de marca da aplicación"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Comproba a configuración do acceso"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"Agora <xliff:g id="SERVICE_NAME">%s</xliff:g> pode ver e controlar a túa pantalla. Toca para revisalo."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 843fe4c40b63..8f85cd1b33fc 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"મોનાર્ક"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"ક્વાર્ટો"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"ફૂલસ્કેપ"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"રૉક 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"કહુ"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"કાકુ2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"અજાણ્યું પોર્ટ્રેટ"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"અજાણ્યું લેન્ડસ્કેપ"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"રદ થઈ"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ઓકે"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે અને બૅકગ્રાઉન્ડમાં થતી પ્રવૃત્તિ, કેટલીક વિઝ્યુઅલ ઇફેક્ટ અને કેટલીક સુવિધાઓને મર્યાદિત કે બંધ કરે છે.\n\n"<annotation id="url">"વધુ જાણો"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે અને બૅકગ્રાઉન્ડમાં થતી પ્રવૃત્તિ, કેટલીક વિઝ્યુઅલ ઇફેક્ટ અને કેટલીક સુવિધાઓને મર્યાદિત કે બંધ કરે છે."</string> <string name="data_saver_description" msgid="4995164271550590517">"ડેટા વપરાશને ઘટાડવામાં સહાય માટે, ડેટા સેવર કેટલીક ઍપને બૅકગ્રાઉન્ડમાં ડેટા મોકલવા અથવા પ્રાપ્ત કરવાથી અટકાવે છે. તમે હાલમાં ઉપયોગ કરી રહ્યાં છો તે ઍપ ડેટાને ઍક્સેસ કરી શકે છે, પરંતુ તે આ ક્યારેક જ કરી શકે છે. આનો અર્થ એ હોઈ શકે છે, ઉદાહરણ તરીકે, છબીઓ ત્યાં સુધી પ્રદર્શિત થશે નહીં જ્યાં સુધી તમે તેને ટૅપ નહીં કરો."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ડેટા સેવર ચાલુ કરીએ?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"ચાલુ કરો"</string> @@ -2099,12 +2085,17 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"નોટિફિકેશનને સાઇલન્ટ પર અવનત કરવામાં આવ્યું. પ્રતિસાદ આપવા માટે ટૅપ કરો."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"આ નોટિફિકેશનને ઉપલી રેંક આપવામાં આવી. પ્રતિસાદ આપવા માટે ટૅપ કરો."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"આ નોટિફિકેશનને નીચલી રેંક આપવામાં આવી. પ્રતિસાદ આપવા માટે ટૅપ કરો."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"વધારાના નોટિફિકેશન અજમાવી જુઓ"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"સૂચવેલી ક્રિયાઓ, જવાબો અને બીજું ઘણું મેળવવા માટે, વધારાના નોટિફિકેશન ચાલુ કરો. Android માટે અનુકૂળ નોટિફિકેશનને હવેથી સપોર્ટ કરવામાં આવતો નથી."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ચાલુ કરો"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"હમણાં નહીં"</string> + <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) --> + <skip /> + <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) --> + <skip /> + <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) --> + <skip /> + <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) --> + <skip /> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"વધુ જાણો"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"વધારાના નોટિફિકેશન સંપર્કનું નામ અને સંદેશા જેવી વ્યક્તિગત માહિતી સહિત નોટિફિકેશનનું બધું કન્ટેન્ટ વાંચી શકે છે. આ સુવિધા નોટિફિકેશન છોડી પણ શકે છે અથવા નોટિફિકેશનમાં બટન પર ફોન કૉલનો જવાબ આપવા જેવી ક્રિયાઓ પણ કરી શકે છે.\n\nઆ સુવિધા પ્રાધાન્યતા મોડ ચાલુ કે બંધ પણ કરી શકે છે અને સંબંધિત સેટિંગ બદલી પણ શકે છે."</string> + <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) --> + <skip /> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"રૂટિન મોડની માહિતીનું નોટિફિકેશન"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"સામાન્ય રીતે ચાર્જ કરવાના સમય પહેલાં બૅટરી સમાપ્ત થઈ શકે છે"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"બૅટરી આવરદા વધારવા માટે બૅટરી સેવર ચાલુ કર્યું"</string> @@ -2301,4 +2292,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ઍપ્લિકેશનની બ્રાંડિંગ છબી"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"ઍક્સેસના સેટિંગ ચેક કરો"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> તમારી સ્ક્રીન જોઈ અને નિયંત્રિત કરી શકે છે. રિવ્યૂ કરવા માટે ટૅપ કરો."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 1419396aa9e0..24f5a4798a2e 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"मोनार्क"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"क्वार्टो"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"फ़ूल्ज़कैप"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"काहु"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"काकु2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"यौ4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"अज्ञात पोर्ट्रेट"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"अज्ञात लैंडस्केप"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"रद्द कर दी गई"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"आपके व्यवस्थापक ने अपडेट किया है"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"आपके व्यवस्थापक ने हटा दिया है"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ठीक है"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"बैटरी सेवर, गहरे रंग वाली थीम को चालू कर देता है. साथ ही, यह बैकग्राउंड में चल रही गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और कुछ खास सुविधाएं इस्तेमाल करने से रोकता है या इन्हें बंद कर देता है.\n\n"<annotation id="url">"ज़्यादा जानें"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"बैटरी सेवर, गहरे रंग वाली थीम को चालू कर देता है. साथ ही, यह बैकग्राउंड में चल रही गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और कुछ खास सुविधाओं के इस्तेमाल को रोकता है या इन्हें बंद कर देता है."</string> <string name="data_saver_description" msgid="4995164271550590517">"डेटा खर्च को कम करने के लिए, डेटा बचाने की सेटिंग कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकती है. फ़िलहाल, आप जिस ऐप्लिकेशन का इस्तेमाल कर रहे हैं वह डेटा ऐक्सेस कर सकता है, लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी जब तक कि आप उन पर टैप नहीं करते."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा बचाने की सेटिंग चालू करें?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"चालू करें"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"इस सूचना के मिलने पर होने वाली आवाज़ बंद कर दी गई है. सुझाव/शिकायत/राय देने के लिए टैप करें."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"इस सूचना को रैंकिंग में ऊपर किया गया था. सुझाव/शिकायत/राय देने के लिए टैप करें."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"इस सूचना को रैंकिंग में नीचे किया गया था. सुझाव/शिकायत/राय देने के लिए टैप करें."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"\'बेहतर सूचनाएं\' सुविधा आज़माएं"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"कार्रवाई और जवाब वगैरह के लिए सुझाव पाना चाहते हैं, तो सूचनाएं पाने की सुविधा बेहतर करें. Android की, ज़रूरत के हिसाब से सूचनाएं पाने की सुविधा अब काम नहीं करती है."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"चालू करें"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"अभी नहीं"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"बेहतर सूचनाएं"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"\'बेहतर सूचनाएं\' सुविधा अब कार्रवाइयों और जवाबों के लिए सुझाव उपलब्ध कराती है. Android की, ज़रूरत के हिसाब से सूचनाएं पाने की सुविधा अब काम नहीं करती है."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"चालू करें"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"बंद करें"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ज़्यादा जानें"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"\'बेहतर सूचनाएं\' सुविधा, डिवाइस पर मिलने वाली सभी सूचनाओं का कॉन्टेंट पढ़ सकती है. इसमें आपकी निजी जानकारी, जैसे कि संपर्कों के नाम और मैसेज भी शामिल हैं. यह सुविधा, डिवाइस पर आने वाली सूचनाओं को रद्द कर सकती है या सूचनाओं में दिखने वाले बटन से कार्रवाइयां भी कर सकती है, जैसे कि फ़ोन कॉल का जवाब देना.\n\nयह सुविधा, प्राथमिकता मोड को चालू या बंद कर सकती है और इससे जुड़ी सेटिंग में बदलाव भी कर सकती है."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 में, ज़रूरत के हिसाब से सूचनाएं पाने की सुविधा की जगह अब \'बेहतर सूचनाएं\' सुविधा काम करेगी. यह सुविधा आपको कार्रवाइयों और जवाबों के सुझाव दिखाती है. साथ ही, आपके डिवाइस में मिलने वाली सूचनाओं को व्यवस्थित भी करती है.\n\n\'बेहतर सूचनाएं\' सुविधा, डिवाइस पर मिलने वाली सभी सूचनाओं का कॉन्टेंट ऐक्सेस कर सकती है. इसमें आपकी निजी जानकारी, जैसे कि संपर्कों के नाम और मैसेज शामिल हैं. यह सुविधा, सूचनाओं को रद्द कर सकती है या उनका जवाब भी दे सकती है, जैसे कि फ़ोन कॉल का जवाब देना और \'परेशान न करें\' को कंट्रोल करना."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"रूटीन मोड जानकारी की सूचना"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"बैटरी आम तौर पर जितने समय चलती है, उससे पहले खत्म हो सकती है"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"बैटरी लाइफ़ बढ़ाने के लिए \'बैटरी सेवर\' चालू हो गया है"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ऐप्लिकेशन की ब्रैंड इमेज"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"ऐक्सेस से जुड़ी सेटिंग देखें"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> आपकी स्क्रीन को देख सकता है और कंट्रोल कर सकता है. ऐक्सेस की समीक्षा करने के लिए टैप करें."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index c88fcbdf7302..edb7c3af48c0 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1731,7 +1731,7 @@ <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 boja"</string> - <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatno zatamnjenje"</string> + <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Još tamnije"</string> <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> @@ -1842,8 +1842,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Nepoznati portret"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Nepoznati pejzaž"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Otkazano"</string> @@ -1888,10 +1887,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao administrator"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao administrator"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"U redu"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Štednja baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizualne efekte i određene značajke.\n\n"<annotation id="url">"Saznajte više"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Štednja baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizualne efekte i određene značajke."</string> <string name="data_saver_description" msgid="4995164271550590517">"Da bi se smanjio podatkovni promet, značajka Štednja podatkovnog prometa onemogućuje nekim aplikacijama slanje ili primanje podataka u pozadini. Aplikacija koju trenutačno upotrebljavate može pristupiti podacima, no možda će to činiti rjeđe. To može značiti da se, na primjer, slike neće prikazivati dok ih ne dodirnete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Uključiti Štednju podatkovnog prometa?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string> @@ -2102,7 +2099,7 @@ <string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"IPAK OTVORI"</string> <string name="harmful_app_warning_title" msgid="8794823880881113856">"Otkrivena je štetna aplikacija"</string> <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> želi prikazivati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string> - <string name="screenshot_edit" msgid="7408934887203689207">"Uređivanje"</string> + <string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string> <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Uređaj će vibrirati za pozive i obavijesti"</string> <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Zvučni signal poziva i obavijesti bit će isključen"</string> <string name="notification_channel_system_changes" msgid="2462010596920209678">"Promjene sustava"</string> @@ -2121,12 +2118,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Obavijest je degradirana u bešumnu. Dodirnite da biste poslali povratne informacije."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Obavijest je više rangirana. Dodirnite da biste poslali povratne informacije."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Obavijest je niže rangirana. Dodirnite da biste poslali povratne informacije."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Proba poboljšanih obavijesti"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Da biste i dalje primali prijedloge za radnje, odgovore i druge informacije, uključite poboljšane obavijesti. Prilagodljive obavijesti za Android više nisu podržane."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Uključi"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ne sad"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Poboljšane obavijesti"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Predložene radnje i odgovori sad se pružaju putem poboljšanih obavijesti. Prilagodljive obavijesti za Android više nisu podržane."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"U redu"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Isključi"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saznajte više"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Poboljšane obavijesti mogu čitati sadržaj svih obavijesti, uključujući osobne podatke kao što su imena kontakata i poruke. Ta značajka može i odbacivati obavijesti ili poduzimati radnje povezane s gumbima u obavijestima kao što je odgovaranje na telefonske pozive.\n\nZnačajka također može uključiti ili isključiti način prioritetnih obavijesti i promijeniti povezane postavke."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"U Androidu 12 poboljšane obavijesti zamjenjuju prilagodljive obavijesti za Android. Ta značajka prikazuje predložene radnje i odgovore te organizira vaše obavijesti.\n\nPoboljšane obavijesti mogu pristupiti sadržaju obavijesti, uključujući osobne podatke kao što su imena kontakata i poruke. Ta značajka može i odbacivati obavijesti ili poduzimati radnje u skladu s njima, na primjer može odgovarati na telefonske pozive i upravljati značajkom Ne uznemiravaj."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obavještavanje o informacijama u Rutinskom načinu rada"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterija se može isprazniti prije uobičajenog vremena punjenja"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Štednja baterije aktivirana je kako bi se produljilo trajanje baterije"</string> @@ -2324,4 +2321,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imidž robne marke aplikacije"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Provjerite postavke pristupa"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> može pregledavati i kontrolirati vaš zaslon. Dodirnite za pregled."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index dcfcfb932550..aa4d42b73ea4 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"„Monarch” méret"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"„Quarto” méret"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"„Foolscap” méret"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"„ROC 8K” méret"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"„ROC 16K” méret"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"„PRC 1” méret"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"„Kahu” méret"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"„Kaku2” méret"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"„You4” méret"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Ismeretlen álló"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Ismeretlen fekvő"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Törölve"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"A rendszergazda által frissítve"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"A rendszergazda által törölve"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, valamint korlátozza vagy kikapcsolja a háttérbeli tevékenységeket, egyes vizuális effekteket és bizonyos funkciókat.\n\n"<annotation id="url">"További információ"</annotation>"."</string> + <string name="battery_saver_description" msgid="5693741424234005958">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, valamint korlátozza vagy kikapcsolja a háttérbeli tevékenységeket, egyes vizuális effekteket és bizonyos funkciókat."</string> <string name="data_saver_description" msgid="4995164271550590517">"Az adatforgalom csökkentése érdekében az Adatforgalom-csökkentő megakadályozza, hogy egyes alkalmazások adatokat küldjenek vagy fogadjanak a háttérben. Az Ön által jelenleg használt alkalmazások hozzáférhetnek az adatokhoz, de csak ritkábban. Ez például azt jelentheti, hogy a képek csak rákoppintás után jelennek meg."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Bekapcsolja az Adatforgalom-csökkentőt?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Bekapcsolás"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Ezt az értesítést némára állította a rendszer. Visszajelzés küldéséhez koppintson ide."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Ezt az értesítést előrébb sorolta a rendszer. Visszajelzés küldéséhez koppintson ide."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Ezt az értesítést hátrébb sorolta a rendszer. Visszajelzés küldéséhez koppintson ide."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Bővített értesítés kipróbálása"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ha továbbra is szeretne kapni javasolt műveleteket, válaszokat és egyebeket, kapcsolja be a bővített értesítéseket. Az androidos alkalmazkodó értesítések már nem támogatottak."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Bekapcsolás"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Most nem"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Bővített értesítések"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Javasolt műveletek és válaszok mostantól bővített értesítésekkel. Az androidos alkalmazkodó értesítések már nem támogatottak."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Kikapcsolás"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"További információ"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"A bővített értesítések minden értesítéstartalmat olvashatnak (így a személyes adatokat, mint például a névjegyek nevét és az üzeneteket is). Ez a funkció emellett elvetheti az értesítéseket, valamint műveleteket végezhet az értesítésekben lévő gombokkal, például felveheti a telefonhívásokat.\n\nEz a funkció a Prioritásos módot is be- vagy kikapcsolhatja, és módosíthatja a kapcsolódó beállításokat."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"A bővített értesítések felváltják az androidos alkalmazkodó értesítéseket az Android 12-es verziójában. Ez a funkció a javasolt műveleteket és válaszokat mutatja, és rendszerezi az értesítéseket.\n\nA bővített értesítések minden értesítéstartalmat olvashatnak (így a személyes adatokat, mint például a névjegyek nevét és az üzeneteket is). Ez a funkció emellett elvetheti az értesítéseket, valamint válaszolhat rájuk, például felveheti a telefonhívásokat, és vezérelheti a Ne zavarjanak módot."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Információs értesítés a rutinmódról"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Előfordulhat, hogy az akkumulátor lemerül a szokásos töltési időszak előtt"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Akkumulátorkímélő mód aktiválva az akkumulátor üzemidejének növelése érdekében"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Alkalmazás márkaképe"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Ellenőrizze a hozzáférési beállításokat"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"A(z) <xliff:g id="SERVICE_NAME">%s</xliff:g> megtekintheti és irányíthatja képernyőjét. Koppintson az áttekintéshez."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 67560f70d7b4..22810e4eebaf 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Անհայտ դիմանկար"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Անհայտ բնապատկեր"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Չեղարկված է"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Թարմացվել է ձեր ադմինիստրատորի կողմից"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Ջնջվել է ձեր ադմինիստրատորի կողմից"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Եղավ"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ։\n\n"<annotation id="url">"Իմանալ ավելին"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ։"</string> <string name="data_saver_description" msgid="4995164271550590517">"Թրաֆիկի տնտեսման ռեժիմում որոշ հավելվածների համար տվյալների ֆոնային փոխանցումն անջատված է։ Հավելվածը, որն օգտագործում եք, կարող է տվյալներ փոխանցել և ստանալ, սակայն ոչ այնքան հաճախ: Օրինակ՝ պատկերները կցուցադրվեն միայն դրանց վրա սեղմելուց հետո։"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Միացնե՞լ թրաֆիկի տնտեսումը"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Միացնել"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Այս ծանուցման կարևորության մակարդակը իջեցվել է և դարձել անձայն։ Հպեք՝ կարծիք հայտնելու համար։"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Այս ծանուցման կարևորության մակարդակը բարձրացվել է։ Հպեք՝ կարծիք հայտնելու համար։"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Այս ծանուցման կարևորության մակարդակն իջեցվել է։ Հպեք՝ կարծիք հայտնելու համար։"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Փորձեք ընդլայնված ծանուցումները"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Միացրեք ընդլայնված ծանուցումները, որպեսզի այսուհետ ևս ստանաք գործողությունների, պատասխանների և այլ առաջարկներ։ Android-ի հարմարվող ծանուցումներն այլևս չեն աջակցվում։"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Միացնել"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ոչ հիմա"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Ընդլայնված ծանուցումներ"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Ընդլայնված ծանուցումներն այժմ տրամադրում են գործողությունների և պատասխանների առաջարկներ։ Android-ի հարմարվող ծանուցումներն այլևս չեն աջակցվում։"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Եղավ"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Անջատել"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Իմանալ ավելին"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Ընդլայնված ծանուցումներին հասանելի է բոլոր ծանուցումների պարունակությունը, ներառյալ անձնական տվյալները, օրինակ՝ կոնտակտների անուններն ու հաղորդագրությունները։ Այս գործառույթը կարող է նաև փակել ծանուցումները կամ ակտիվացնել դրանցում առկա կոճակները, այդ թվում՝ պատասխանել հեռախոսազանգերի։\n\nԱյս գործառույթը կարող է նաև միացնել/անջատել «Միայն կարևորները» ռեժիմը և փոխել համապատասխան կարգավորումները։"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12-ում ընդլայնված ծանուցումները փոխարինում են Android-ի հարմարվող ծանուցումներին։ Այս գործառույթը դասավորում է ձեր բոլոր ծանուցումները և առաջարկում գործողություններ և պատասխաններ։\n\nԸնդլայնված ծանուցումներին հասանելի է բոլոր ծանուցումների պարունակությունը, ներառյալ անձնական տվյալները, օրինակ՝ կոնտակտների անուններն ու հաղորդագրությունները։ Այս գործառույթը կարող է նաև փակել ծանուցումները կամ սեղմել դրանցում առկա կոճակները, այդ թվում՝ պատասխանել հեռախոսազանգերի և կառավարել «Չանհանգստացնել» ռեժիմը։"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ծանուցում լիցքավորման մասին"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Մարտկոցը կարող է սովորականից շուտ սպառվել"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Մարտկոցի կյանքը երկարացնելու համար ակտիվացվել է մարտկոցի տնտեսման ռեժիմը"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Հավելվածի բրենդային պատկեր"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Ստուգեք մուտքի կարգավորումները"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ծառայությունը կարող է դիտել և կառավարել ձեր էկրանի բովանդակությունը։ Հպեք՝ մանրամասներն իմանալու համար։"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index d85a4ba36da6..94a501a616bd 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Kuarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Folio"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Potret tidak diketahui"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Lanskap tidak diketahui"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Dibatalkan"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Diupdate oleh admin Anda"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Dihapus oleh admin Anda"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Oke"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Penghemat Baterai mengaktifkan Tema gelap dan membatasi atau menonaktifkan aktivitas latar belakang, beberapa efek visual, dan fitur tertentu.\n\n"<annotation id="url">"Pelajari lebih lanjut"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Penghemat Baterai mengaktifkan Tema gelap dan membatasi atau menonaktifkan aktivitas latar belakang, beberapa efek visual, dan fitur tertentu."</string> <string name="data_saver_description" msgid="4995164271550590517">"Untuk membantu mengurangi penggunaan data, Penghemat Data mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah diketuk."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Aktifkan Penghemat Data?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Aktifkan"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Notifikasi ini didemosikan menjadi Senyap. Ketuk untuk memberikan masukan."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Notifikasi ini diberi peringkat lebih tinggi. Ketuk untuk memberikan masukan."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Notifikasi ini diberi peringkat lebih rendah. Ketuk untuk memberikan masukan."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Coba notifikasi yang disempurnakan"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Untuk terus mendapatkan saran tindakan, balasan, dan lainnya, aktifkan notifikasi yang disempurnakan. Notifikasi Adaptif Android tidak lagi didukung."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktifkan"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Lain kali"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notifikasi yang ditingkatkan"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Tindakan dan balasan yang disarankan kini diberikan oleh notifikasi yang ditingkatkan. Notifikasi Adaptif Android tidak lagi didukung."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Oke"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Nonaktifkan"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Pelajari lebih lanjut"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Notifikasi yang disempurnakan dapat membaca semua isi notifikasi, termasuk informasi pribadi seperti nama kontak dan pesan. Fitur ini juga dapat menutup notifikasi atau memicu tindakan pada tombol di notifikasi, seperti menjawab panggilan telepon.\n\nFitur ini juga dapat mengaktifkan atau menonaktifkan mode Prioritas dan mengubah setelan terkait."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Notifikasi yang ditingkatkan menggantikan Notifikasi Adaptif Android di Android 12. Fitur ini menunjukkan tindakan dan balasan yang disarankan, dan mengatur notifikasi.\n\nNotifikasi yang ditingkatkan dapat mengakses konten notifikasi, termasuk informasi pribadi seperti nama kontak dan pesan. Fitur ini juga dapat menutup atau merespons notifikasi, seperti menjawab panggilan telepon dan mengontrol Jangan Ganggu."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifikasi info Mode Rutinitas"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterai mungkin habis sebelum pengisian daya biasanya"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Penghemat Baterai diaktifkan untuk memperpanjang masa pakai baterai"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Brand image aplikasi"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Periksa setelan akses"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> dapat melihat dan mengontrol layar Anda. Ketuk untuk meninjau."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 5ae655405d5a..0a7fa5bff8dd 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Örk A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Örk B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Örk C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Örk D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Örk E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Örk E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Óþekkt skammsnið"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Óþekkt langsnið"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Hætt við"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Kerfisstjóri uppfærði"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Kerfisstjóri eyddi"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Í lagi"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Rafhlöðusparnaður kveikir á dökku þema og dregur úr eða slekkur á bakgrunnsvirkni, sumum myndáhrifum og tilteknum eiginleikum.\n\n"<annotation id="url">"Nánar"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Rafhlöðusparnaður kveikir á dökku þema og dregur úr eða slekkur á bakgrunnsvirkni, sumum myndáhrifum og tilteknum eiginleikum."</string> <string name="data_saver_description" msgid="4995164271550590517">"Gagnasparnaður getur hjálpað til við að draga úr gagnanotkun með því að hindra forrit í að senda eða sækja gögn í bakgrunni. Forrit sem er í notkun getur náð í gögn, en gerir það kannski sjaldnar. Niðurstaðan getur verið að myndir eru ekki birtar fyrr en þú ýtir á þær, svo dæmi sé tekið."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Kveikja á gagnasparnaði?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Kveikja"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Þessi tilkynning var gerð þögul. Ýttu til að senda ábendingu."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Þessi tilkynning fékk hærri stöðu. Ýttu til að senda ábendingu."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Þessi tilkynning fékk lægri stöðu. Ýttu til að senda ábendingu."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prófa auknar tilkynningar"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Kveiktu á auknum tilkynningum til að halda áfram að fá tillögur að aðgerðum, svörum og fleira. Breytilegar tilkynningar í Android eru ekki lengur studdar."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Kveikja"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ekki núna"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Auknar tilkynningar"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Auknar tilkynningar bjóða nú upp á tillögur að aðgerðum og svörum. Breytilegar tilkynningar í Android eru ekki lengur studdar."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Í lagi"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Slökkva"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Nánar"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Auknar tilkynningar geta lesið allt efni tilkynninga, þar á meðal persónuupplýsingar á borð við nöfn tengiliða og skilaboð. Þessi eiginleiki getur einnig hunsað tilkynningar eða notað hnappa í tilkynningum eins og að svara símtölum.\n\nÞessi eiginleiki getur einnig kveikt og slökkt á forgangsstillingu og breytt tengdum stillingum."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Auknar tilkynningar hafa leyst breytilegar tilkynningar í Android af hólmi í Android 12. Eiginleikinn birtir tillögur að aðgerðum og svörum og flokkar tilkynningar.\n\nAuknar tilkynningar hafa aðgang að efni tilkynninga, þ. á m persónuupplýsingum á borð við nöfn tengiliða og skilaboð. Eiginleikinn getur einnig hunsað eða svarað tilkynningum, til dæmis svarað símtölum og stjórnað „Ónáðið ekki“."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Upplýsingatilkynning aðgerðastillingar"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Rafhlaðan kann að tæmast áður en hún kemst í hleðslu"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Kveikt á rafhlöðusparnaði til að lengja endingu rafhlöðunnar"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Mynd af merki forrits"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Skoða aðgangsstillingar"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> getur skoðað og stjórnað skjánum hjá þér. Ýttu til að skoða."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 0a3e014e433f..184ca91dde0c 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Verticale sconosciuto"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Orizzontale sconosciuto"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Annullato"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Aggiornato dall\'amministratore"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"La funzionalità Risparmio energetico attiva il tema scuro e limita o disattiva le attività in background, alcuni effetti visivi e funzionalità.\n\n"<annotation id="url">"Scopri di più"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"La funzionalità Risparmio energetico attiva il tema scuro e limita o disattiva le attività in background, alcuni effetti visivi e funzionalità."</string> <string name="data_saver_description" msgid="4995164271550590517">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Attivare Risparmio dati?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Attiva"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Questa notifica è stata retrocessa a Silenziosa. Tocca per dare un feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Questa notifica è stata posizionata più in alto. Tocca per dare un feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Questa notifica è stata posizionata più in basso. Tocca per dare un feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prova le notifiche avanzate"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Per continuare a ricevere suggerimenti di azioni, risposte e altro, attiva le notifiche avanzate. Le notifiche adattive Android non sono più supportate."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Attiva"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Non ora"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notifiche avanzate"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Ora le risposte e le azioni suggerite vengono fornite dalle notifiche avanzate. Le notifiche adattive Android non sono più supportate."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Disattiva"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Scopri di più"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Le notifiche avanzate possono accedere all\'intero contenuto di una notifica, incluse le informazioni personali, come i nomi dei contatti e i messaggi. Questa funzionalità può anche ignorare le notifiche o svolgere azioni sui pulsanti nelle notifiche, come rispondere alle telefonate.\n\nQuesta funzionalità può anche attivare o disattivare la modalità Priorità e modificare le relative impostazioni."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Le notifiche adattive Android sono state sostituite dalle notifiche avanzate in Android 12. Questa funzionalità mostra risposte e azioni suggerite e organizza le tue notifiche.\n\nLe notifiche avanzate possono accedere ai contenuti di una notifica, incluse le informazioni personali, come i nomi dei contatti e i messaggi. Questa funzionalità può anche ignorare le notifiche o rispondervi, ad esempio accettando le telefonate e controllando Non disturbare."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifica di informazioni sulla modalità Routine"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"La batteria potrebbe esaurirsi prima della ricarica abituale"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Risparmio energetico attivo per far durare di più la batteria"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Immagine del branding dell\'applicazione"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Controlla le impostazioni di accesso"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> può visualizzare e controllare il tuo schermo. Tocca per verificare."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 6bfb7ebf1db9..aecd79bd6527 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1817,28 +1817,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super-B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1875,8 +1864,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"הדפסה לאורך בגודל לא ידוע"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"הדפסה לרוחב בגודל לא ידוע"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"בוטלה"</string> @@ -1922,10 +1910,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"עודכנה על ידי מנהל המערכת"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"נמחקה על ידי מנהל המערכת"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"אישור"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה את הפעילות ברקע, חלק מהאפקטים החזותיים ותכונות מסוימות.\n\n"<annotation id="url">"מידע נוסף"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה את הפעילות ברקע, חלק מהאפקטים החזותיים ותכונות מסוימות."</string> <string name="data_saver_description" msgid="4995164271550590517">"כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות לשלוח או לקבל נתונים ברקע. אפליקציות שבהן נעשה שימוש כרגע יכולות לגשת לנתונים, אבל בתדירות נמוכה יותר. המשמעות היא, למשל, שתמונות יוצגו רק לאחר שמקישים עליהן."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"להפעיל את חוסך הנתונים?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"הפעלה"</string> @@ -2165,12 +2151,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ההתראה הזו הורדה בדרגה ל\'שקטה\'. יש להקיש כדי לשלוח משוב."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"דירוג ההתראה הזו הוגבה. יש להקיש כדי לשלוח משוב."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ההתראה הזו דורגה נמוך יותר. יש להקיש כדי לשלוח משוב."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"רוצה לנסות את ההתראות המשופרות?"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"כדי להמשיך לקבל הצעות לפעולות, לתשובות ועוד, יש להפעיל את ההתראות המשופרות. אין יותר תמיכה בהתראות מותאמות ל-Android."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"הפעלה"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"לא עכשיו"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"התראות משופרות"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"ההתראות המשופרות מספקות מעכשיו הצעות לפעולות ולתשובות. אין יותר תמיכה בהתראות מותאמות ל-Android."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"אישור"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"השבתה"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"מידע נוסף"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"כשתכונת ההתראות המשופרות פועלת, המערכת יכולה לקרוא את כל תוכן ההתראות, כולל מידע אישי כמו שמות של אנשי קשר והודעות. כמו כן, התכונה תוכל לסגור התראות או לבצע פעולות שהן כוללות, כמו מענה לשיחות טלפון.\n\nהתכונה תוכל גם להפעיל או להשבית את מצב העדיפות ולשנות את ההגדרות הקשורות."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"ההתראות המשופרות החליפו את ההתראות המותאמות ל-Android ב-Android 12. התכונה הזו מציגה הצעות לפעולות ולתשובות ומארגנת את ההתראות שלך.\n\nההתראות המשופרות יכולות לקבל גישה לתוכן של התראות, כולל מידע אישי כמו שמות אנשי קשר והודעות. התכונה הזו יכולה גם לסגור התראות או להשיב להן, למשל מענה לשיחות טלפון ושליטה בתכונה \'נא לא להפריע\'."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"התראת מידע לגבי מצב שגרתי"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"הסוללה עלולה להתרוקן לפני המועד הרגיל של הטעינה"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"תכונת החיסכון בסוללה הופעלה כדי להאריך את חיי הסוללה"</string> @@ -2369,4 +2355,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"תדמית המותג של האפליקציה"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"בדיקה של הגדרות הגישה"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"לשירות <xliff:g id="SERVICE_NAME">%s</xliff:g> יש הרשאה להצגת המסך ושליטה בו. אפשר להקיש כדי לבדוק."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index bed82eb1042a..90495be9d06a 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"モナーク"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"クォート"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"フールスキャップ"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"角2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"洋4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"縦向き不明"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"横向き不明"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"キャンセルされました"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"管理者により更新されています"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"管理者により削除されています"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"バッテリー セーバーを有効にすると、ダークテーマが ON になり、バックグラウンド アクティビティ、一部の視覚効果、特定の機能が制限されるか OFF になります。\n\n"<annotation id="url">"詳細"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"バッテリー セーバーを有効にすると、ダークテーマが ON になり、バックグラウンド アクティビティ、一部の視覚効果、特定の機能が制限されるか OFF になります。"</string> <string name="data_saver_description" msgid="4995164271550590517">"データセーバーは、一部のアプリによるバックグラウンドでのデータ送受信を停止することでデータ使用量を抑制します。使用中のアプリからデータを送受信することはできますが、その頻度は低くなる場合があります。この影響として、たとえば画像はタップしないと表示されないようになります。"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"データセーバーを ON にしますか?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"ON にする"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"この通知の重要度がサイレントに下がりました。タップしてフィードバックをお送りください。"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"この通知の重要度が上がりました。タップしてフィードバックをお送りください。"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"この通知の重要度が下がりました。タップしてフィードバックをお送りください。"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"拡張通知を使ってみる"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"操作や返信の候補などを利用し続けるには、拡張通知を ON にしてください。Android 通知の自動調整はサポートを終了しました。"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ON にする"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"後で"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"拡張通知"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"操作や返信の候補が拡張通知から提供されるようになりました。Android 通知の自動調整はサポートを終了しました。"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"OFF にする"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"詳細"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"拡張通知はすべての通知コンテンツにアクセスできます。これには、連絡先の名前などの個人情報やメッセージも含まれます。また、通知を非表示にしたり、電話に出るなど、通知内の操作ボタンを実行したりすることもできます。\n\nまた、この機能は、優先モードの設定を切り替えたり、関連する設定を変更したりすることもできます。"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 では Android 通知の自動調整が拡張通知に切り替えられました。この機能により、操作や返信の候補が提示され、通知が整理されます。\n\n拡張通知は通知コンテンツにアクセスできます。これには、連絡先の名前などの個人情報やメッセージも含まれます。また、この機能は、通知を非表示にしたり通知に応答したりすることもできます。たとえば、電話に出ることやサイレント モードを管理することができます。"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ルーティン モード情報の通知"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"通常の充電を行う前に電池が切れる可能性があります"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"電池を長持ちさせるため、バッテリー セーバーが有効になりました"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"アプリのブランド イメージ"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"アクセス設定の確認"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> は画面を参照、操作できます。タップしてご確認ください。"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index a7d11c251f17..3f1c8b6a67cb 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"დიდი"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"უცნობი პორტრეტი"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"უცნობი ლანდშაფტი"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"გაუქმებული"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"წაიშალა თქვენი ადმინისტრატორის მიერ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"კარგი"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ბატარეის დამზოგი ჩართავს მუქ თემას და შეზღუდავს ან გამორთავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტსა და გარკვეულ ფუნქციებს.\n\n"<annotation id="url">"შეიტყვეთ მეტი"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"ბატარეის დამზოგი ჩართავს მუქ თემას და შეზღუდავს ან გამორთავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტსა და გარკვეულ ფუნქციებს."</string> <string name="data_saver_description" msgid="4995164271550590517">"მობილური ინტერნეტის მოხმარების შემცირების მიზნით, მონაცემთა დამზოგველი ზოგიერთ აპს ფონურ რეჟიმში მონაცემთა გაგზავნასა და მიღებას შეუზღუდავს. თქვენ მიერ ამჟამად გამოყენებული აპი მაინც შეძლებს მობილურ ინტერნეტზე წვდომას, თუმცა ამას ნაკლები სიხშირით განახორციელებს. ეს ნიშნავს, რომ, მაგალითად, სურათები არ გამოჩნდება მანამ, სანამ მათ საგანგებოდ არ შეეხებით."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ჩაირთოს მონაცემთა დამზოგველი?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"ჩართვა"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ეს შეტყობინება ჩამოქვეითდა და გახდა „ჩუმი“. შეეხეთ გამოხმაურების მოსაწოდებლად."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ეს შეტყობინება დაწინაურდა. შეეხეთ გამოხმაურების მოსაწოდებლად."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ეს შეტყობინება ჩამოქვეითდა. შეეხეთ გამოხმაურების მოსაწოდებლად."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"გამოცადეთ გაფართოებული შეტყობინებები"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"შემოთავაზებული ქმედებების, პასუხების და სხვა მითითებების მიღების გასაგრძელებლად ჩართეთ გაფართოებული შეტყობინებები. Android-ის ადაპტაციური შეტყობინებები აღარაა მხარდაჭერილი."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ჩართვა"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ახლა არა"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"გაფართოებული შეტყობინებები"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"შემოთავაზებული მოქმედებები და პასუხები ამიერიდან უზრუნველყოფილია გაფართოებული შეტყობინებების მიერ. Android-ის ადაპტაციური შეტყობინებები აღარაა მხარდაჭერილი."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"კარგი"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"გამორთვა"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"შეიტყვეთ მეტი"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"გაფართოებულ შეტყობინებებს შეუძლია ყველა შეტყობინების კონტენტის, მათ შორის, ისეთი პერსონალური ინფორმაციის წაკითხვა, როგორიცაა კონტაქტების სახელები და შეტყობინებები. ამ ფუნქციას ასევე შეუძლია შეტყობინებების დახურვა ან შეტყობინებათა ღილაკების ამოქმედება, მაგალითად, სატელეფონო ზარებზე პასუხი.\n\nამ ფუნქციას ასევე შეუძლია პრიორიტეტული რეჟიმის ჩართვა თუ გამორთვა და დაკავშირებული პარამეტრების შეცვლა."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"გაფართოებულმა შეტყობინებებმა ჩაანაცვლა Android-ის ადაპტაციური შეტყობინებების ფუნქცია Android 12-ში. ეს ფუნქცია გაჩვენებთ შემოთავაზებულ მოქმედებებს და პასუხებს, ამასთანავე კი ახდენს თქვენი შეტყობინებების ორგანიზებას.\n\nგაფართოებულ შეტყობინებებს შეუძლია ყველა შეტყობინების კონტენტზე, მათ შორის, ისეთ პერსონალურ ინფორმაციაზე წვდომა, როგორიცაა კონტაქტების სახელები და შეტყობინებები. ამ ფუნქციას ასევე შეუძლია შეტყობინებათა დახურვა ან მათზე პასუხის გაცემა, მაგალითად, სატელეფონო ზარებზე პასუხი და „არ შემაწუხოთ“ რეჟიმის მართვა."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"რუტინის რეჟიმის საინფორმაციო შეტყობინება"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ბატარეა შეიძლება დაჯდეს დატენის ჩვეულ დრომდე"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ბატარეის დამზოგი გააქტიურდა ბატარეის მუშაობის გასახანგრძლივლებლად"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"აპლიკაციის ბრენდის სურათი"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"სწრაფი წვდომის პარამეტრები"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g>-ს შეუძლია თქვენი ეკრანის ნახვა და მართვა. შეეხეთ გადასახედად."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 402256e5e51e..261426414701 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -1707,7 +1707,7 @@ <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Дайын"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Төте жолды өшіру"</string> <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Төте жолды пайдалану"</string> - <string name="color_inversion_feature_name" msgid="326050048927789012">"Түстер инверсиясы"</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="3222994553174604132">"Экранды қарайту"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Пайдаланушы дыбыс деңгейі пернелерін басып ұстап тұрды. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қосулы."</string> @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Монарх"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Кварто"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Белгісіз портреттік"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Белгісіз ландшафт"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Тоқтатылды"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Әкімші жаңартқан"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Әкімші жойған"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Жарайды"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады және фондық әрекеттерге, кейбір визуалдық әсерлер мен белгілі бір функцияларға шектеу қояды немесе оларды өшіреді.\n\n"<annotation id="url">"Толығырақ"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады және фондық әрекеттерге, кейбір визуалдық әсерлер мен белгілі бір функцияларға шектеу қояды немесе оларды өшіреді."</string> <string name="data_saver_description" msgid="4995164271550590517">"Дерек шығынын азайту үшін Трафикті үнемдеу режимінде кейбір қолданбаларға деректі фондық режимде жіберуге және алуға тыйым салынады. Ашық тұрған қолданба деректі шектеулі шамада пайдаланады (мысалы, кескіндер оларды түрткенге дейін көрсетілмейді)."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Трафикті үнемдеу режимі қосылсын ба?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Қосу"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Бұл хабарландырудың маңыздылық деңгейі \"Үнсіз\" санатына төмендетілді. Пікір қалдыру үшін түртіңіз."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Бұл хабарландырудың маңыздылық деңгейі көтерілді. Пікір қалдыру үшін түртіңіз."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Бұл хабарландырудың маңыздылық деңгейі төмендетілді. Пікір қалдыру үшін түртіңіз."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Кеңейтілген хабарландыруларды пайдалану"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ұсынылған әрекеттер, жауаптар және т.б. алып отыру үшін \"Кеңейтілген хабарландырулар\" функциясын қосыңыз. Android-тың \"Бейімделетін хабарландырулар\" функциясына бұдан былай қолдау көрсетілмейді."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Қосу"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Қазір емес"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Кеңейтілген хабарландырулар"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Ұсынылған әрекеттер мен жауаптар енді кеңейтілген хабарландырулар функциясы арқылы қамтамасыз етіледі. Android-тың \"Бейімделетін хабарландырулар\" функциясына бұдан былай қолдау көрсетілмейді."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Жарайды"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Өшіру"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Толығырақ"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"\"Кеңейтілген хабарландырулар\" функциясы барлық хабарландыру мазмұнын (контакт атаулары мен хабарлар сияқты жеке ақпаратты қоса алғанда) оқи алады. Сондай-ақ бұл функция арқылы хабарландыруларды жабуға немесе хабарландырулардағы түймелерді басқаруға (мысалы, телефон қоңырауларына жауап беру) болады.\n\nОл арқылы \"Маңызды\" режимін қосуға немесе өшіруге, қатысты параметрлерді өзгертуге де болады."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 жүйесінде кеңейтілген хабарландырулар функциясы \"Бейімделетін хабарландырулар\" функциясын алмастырды. Бұл функция ұсынылған әрекеттер мен жауаптарды көрсетіп, хабарландыруларыңызды ретке келтіреді.\n\nОл хабарландыру мазмұнын, соның ішінде жеке ақпаратыңызды (мысалы, контакт атаулары мен хабарлар) пайдалана алады. Сондай-ақ бұл функция арқылы хабарландыруларды жабуға немесе оларға жауап беруге (мысалы, телефон қоңырауларына жауап беру және \"Мазаламау\" режимін басқару) болады."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Режим туралы хабарландыру"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарея заряды азаюы мүмкін"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Батарея ұзаққа жетуі үшін, Батареяны үнемдеу режимі іске қосылды"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Қолданба брендін ілгері жылжыту кескіні"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Пайдалану параметрлерін тексеріңіз"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> экраныңызды көріп, оны басқара алады. Өту үшін түртіңіз."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 47946ddfaae1..e00bed0f0164 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"ធំ"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"មិនស្គាល់បញ្ឈរ"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"មិនស្គាល់ទេសភាព"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"បានបោះបង់"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"ធ្វើបច្ចុប្បន្នភាពដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"លុបដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"យល់ព្រម"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"មុខងារសន្សំថ្មបើករចនាប័ទ្មងងឹត និងដាក់កំហិត ឬបិទសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលរូបភាពមួយចំនួន និងមុខងារជាក់លាក់។\n\n"<annotation id="url">"ស្វែងយល់បន្ថែម"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"មុខងារសន្សំថ្មបើករចនាប័ទ្មងងឹត និងដាក់កំហិត ឬបិទសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលរូបភាពមួយចំនួន និងមុខងារជាក់លាក់។"</string> <string name="data_saver_description" msgid="4995164271550590517">"ដើម្បីជួយកាត់បន្ថយការប្រើប្រាស់ទិន្នន័យ កម្មវិធីសន្សំសំចៃទិន្នន័យរារាំងកម្មវិធីមួយចំនួនមិនឲ្យបញ្ជូន ឬទទួលទិន្នន័យនៅផ្ទៃខាងក្រោយទេ។ កម្មវិធីដែលអ្នកកំពុងប្រើនាពេលបច្ចុប្បន្នអាចចូលប្រើប្រាស់ទិន្នន័យបាន ប៉ុន្តែអាចនឹងមិនញឹកញាប់ដូចមុនទេ។ ឧទាហរណ៍ រូបភាពមិនបង្ហាញទេ លុះត្រាតែអ្នកប៉ះរូបភាពទាំងនោះ។"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"បើកកម្មវិធីសន្សំសំចៃទិន្នន័យ?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"បើក"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ការជូនដំណឹងនេះត្រូវបានបន្ទាបតំណែងទៅស្ងាត់។ សូមចុចដើម្បីផ្ដល់មតិកែលម្អ។"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ការជូនដំណឹងនេះត្រូវបានចាត់ថ្នាក់ខ្ពស់ជាងមុន។ សូមចុចដើម្បីផ្ដល់មតិកែលម្អ។"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ការជូនដំណឹងនេះត្រូវបានចាត់ថ្នាក់ទាបជាងមុន។ សូមចុចដើម្បីផ្ដល់មតិកែលម្អ។"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"សាកល្បងប្រើការជូនដំណឹងប្រសើរជាងមុន"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"ដើម្បីបន្តទទួលបានការឆ្លើយតប សកម្មភាពដែលបានណែនាំ និងអ្វីៗជាច្រើនទៀត សូមបើកការជូនដំណឹងប្រសើរជាងមុន។ ការជូនដំណឺងដែលមានភាពបត់បែន Android មិនអាចប្រើបានទៀតទេ។"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"បើក"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"កុំទាន់"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"ការជូនដំណឹងប្រសើរជាងមុន"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"ឥឡូវនេះ ការឆ្លើយតប និងសកម្មភាពដែលបានណែនាំត្រូវបានផ្ដល់ដោយការជូនដំណឹងប្រសើរជាងមុន។ មិនអាចប្រើការជូនដំណឹងដែលមានភាពបត់បែនរបស់ Android បានទៀតទេ។"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"យល់ព្រម"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"បិទ"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ស្វែងយល់បន្ថែម"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"ការជូនដំណឹងប្រសើរជាងមុនអាចអានខ្លឹមសារជូនដំណឹងទាំងអស់ រួមទាំងព័ត៌មានផ្ទាល់ខ្លួនដូចជា ឈ្មោះទំនាក់ទំនង និងសារជាដើម។ មុខងារនេះក៏អាចច្រានចោលការជូនដំណឹង ឬធ្វើសកម្មភាពលើប៊ូតុងនៅក្នុងការជូនដំណឹងផងដែរ ដូចជាការទទួលការហៅទូរសព្ទជាដើម។\n\nមុខងារនេះក៏អាចបើកឬបិទមុខងារអាទិភាព និងផ្លាស់ប្ដូរការកំណត់ដែលពាក់ព័ន្ធផងដែរ។"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"ការជូនដំណឹងប្រសើរជាងមុនបានជំនួសការជូនដំណឹងដែលមានភាពបត់បែន Android នៅក្នុង Android 12។ មុខងារនេះបង្ហាញការឆ្លើយតប និងសកម្មភាពដែលបានណែនាំ ព្រមទាំងរៀបចំការជូនដំណឹងរបស់អ្នក។\n\nការជូនដំណឹងប្រសើរជាងមុនអាចចូលប្រើខ្លឹមសារនៃការជូនដំណឹង រួមទាំងព័ត៌មានផ្ទាល់ខ្លួនដូចជា ឈ្មោះទំនាក់ទំនង និងសារជាដើម។ មុខងារនេះក៏អាចច្រានចោល ឬឆ្លើយតបនឹងការជូនដំណឹងដូចជា ការទទួលការហៅទូរសព្ទ និងការគ្រប់គ្រងមុខងារកុំរំខានផងដែរ។"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ការជូនដំណឹងព័ត៌មានរបស់មុខងារទម្លាប់"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ថ្មអាចនឹងអស់ មុនពេលសាកថ្មធម្មតា"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"បានបើកដំណើរការមុខងារសន្សំថ្ម ដើម្បីបង្កើនកម្រិតថាមពលថ្ម"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"រូបភាពផ្សព្វផ្សាយម៉ាកកម្មវិធី"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"ពិនិត្យមើលការកំណត់សិទ្ធិចូលប្រើ"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> អាចមើល និងគ្រប់គ្រងអេក្រង់របស់អ្នកបាន។ សូមចុច ដើម្បីពិនិត្យមើល។"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index c4606d65e9e2..7ac785bd60f7 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"ಮೊನಾರ್ಕ್"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"ಕ್ವಾರ್ಟೊ"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"ಅಪರಿಚಿತ ಪೋರ್ಟ್ರೇಟ್"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"ಅಪರಿಚಿತ ಲ್ಯಾಂಡ್ಸ್ಕೇಪ್"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ರದ್ದುಮಾಡಲಾಗಿದೆ"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ಸರಿ"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್ಗಳು, ಮತ್ತು ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ.\n\n"<annotation id="url">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್ಗಳು, ಮತ್ತು ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ."</string> <string name="data_saver_description" msgid="4995164271550590517">"ಡೇಟಾ ಬಳಕೆ ಕಡಿಮೆ ಮಾಡುವ ನಿಟ್ಟಿನಲ್ಲಿ, ಡೇಟಾ ಸೇವರ್ ಕೆಲವು ಅಪ್ಲಿಕೇಶನ್ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಡೇಟಾ ಕಳುಹಿಸುವುದನ್ನು ಅಥವಾ ಸ್ವೀಕರಿಸುವುದನ್ನು ತಡೆಯುತ್ತದೆ. ನೀವು ಪ್ರಸ್ತುತ ಬಳಸುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು ಆದರೆ ಪದೇ ಪದೇ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಇದರರ್ಥ, ಉದಾಹರಣೆಗೆ, ನೀವು ಅವುಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವವರೆಗೆ ಆ ಚಿತ್ರಗಳು ಕಾಣಿಸಿಕೊಳ್ಳುವುದಿಲ್ಲ."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ಡೇಟಾ ಸೇವರ್ ಆನ್ ಮಾಡಬೇಕೇ?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"ಆನ್ ಮಾಡಿ"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ಈ ಅಧಿಸೂಚನೆಗೆ ಸೈಲೆಂಟ್ಗೆ ಹಿಂಬಡ್ತಿ ನೀಡಲಾಗಿದೆ. ಪ್ರತಿಕ್ರಿಯೆ ನೀಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ಈ ಅಧಿಸೂಚನೆಗೆ ಮೇಲಿನ ಸ್ಥಾನವನ್ನು ನೀಡಲಾಗಿದೆ. ಪ್ರತಿಕ್ರಿಯೆ ನೀಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ಈ ಅಧಿಸೂಚನೆಗೆ ಕೆಳಗಿನ ಸ್ಥಾನವನ್ನು ನೀಡಲಾಗಿದೆ. ಪ್ರತಿಕ್ರಿಯೆ ನೀಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"ವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳು ಪ್ರಯತ್ನಿಸಿ"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"ಸೂಚಿಸಲಾದ ಕ್ರಿಯೆಗಳು, ಪ್ರತ್ಯುತ್ತರಗಳು ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ಪಡೆಯಲು, ವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳನ್ನು ಆನ್ ಮಾಡಿ. Android ಅಡಾಪ್ಟಿವ್ ಅಧಿಸೂಚನೆಗಳು ಇನ್ನು ಮುಂದೆ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ಆನ್ ಮಾಡಿ"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ಈಗ ಬೇಡ"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"ವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳು"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"ಸೂಚಿಸಲಾದ ಕ್ರಿಯೆಗಳು ಮತ್ತು ಪ್ರತ್ಯುತ್ತರಗಳನ್ನು ಈಗ ವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳಿಂದ ಒದಗಿಸಲಾಗಿದೆ. Android ಅಡಾಪ್ಟಿವ್ ಅಧಿಸೂಚನೆಗಳು ಇನ್ನು ಮುಂದೆ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ಸರಿ"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ಆಫ್ ಮಾಡಿ"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"ವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳು ಸಂಪರ್ಕ ಹೆಸರುಗಳು ಮತ್ತು ಸಂದೇಶಗಳಂತಹ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆ ವಿಷಯವನ್ನು ಓದಬಹುದು. ಈ ವೈಶಿಷ್ಟ್ಯವು ಅಧಿಸೂಚನೆಗಳನ್ನು ವಜಾಗೊಳಿಸಬಹುದು ಅಥವಾ ಫೋನ್ ಕರೆಗಳಿಗೆ ಉತ್ತರಿಸುವಂತಹ ಅಧಿಸೂಚನೆಗಳಲ್ಲಿನ ಬಟನ್ಗಳಿಗೆ ಸಂಬಂಧಿಸಿದ ಕ್ರಮ ತೆಗೆದುಕೊಳ್ಳಬಹುದು.\n\nಈ ವೈಶಿಷ್ಟ್ಯವು ಆದ್ಯತಾ ಮೋಡ್ ಅನ್ನು ಆನ್ ಅಥವಾ ಆಫ್ ಮಾಡಬಹುದು ಮತ್ತು ಸಂಬಂಧಿತ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಬಹುದು."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"ವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳು Android 12 ರಲ್ಲಿ ಆಂಡ್ರಾಯ್ಡ್ ಅಡಾಪ್ಟಿವ್ ಅಧಿಸೂಚನೆಗಳನ್ನು ಬದಲಾಯಿಸಿವೆ. ಈ ವೈಶಿಷ್ಟ್ಯವು ಸೂಚಿಸಿದ ಕ್ರಿಯೆಗಳು ಮತ್ತು ಪ್ರತ್ಯುತ್ತರಗಳನ್ನು ತೋರಿಸುತ್ತದೆ ಮತ್ತು ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳನ್ನು ಆಯೋಜಿಸುತ್ತದೆ.\n\nವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳು ಸಂಪರ್ಕ ಹೆಸರುಗಳು ಮತ್ತು ಸಂದೇಶಗಳಂತಹ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆ ವಿಷಯವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು. ಈ ವೈಶಿಷ್ಟ್ಯವು ಫೋನ್ ಕರೆಗಳಿಗೆ ಉತ್ತರಿಸುವುದು ಮತ್ತು \'ಅಡಚಣೆ ಮಾಡಬೇಡಿ\' ಅನ್ನು ನಿಯಂತ್ರಿಸುವಂತಹ ಅಧಿಸೂಚನೆಗಳನ್ನು ವಜಾಗೊಳಿಸಬಹುದು ಅಥವಾ ಪ್ರತಿಕ್ರಿಯಿಸಬಹುದು."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ದೈನಂದಿನ ಸ್ಥಿತಿಯ ಮಾಹಿತಿಯ ಅಧಿಸೂಚನೆ"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ಚಾರ್ಜ್ಗೆ ಮೊದಲೆ ಬ್ಯಾಟರಿ ಮುಗಿದು ಬಿಡಬಹುದು"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ಬ್ಯಾಟರಿ ಅವಧಿ ಹೆಚ್ಚಿಸಲು ಬ್ಯಾಟರಿ ಸೇವರ್ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ಅಪ್ಲಿಕೇಶನ್ ಬ್ರ್ಯಾಂಡಿಂಗ್ ಚಿತ್ರ"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"ಪ್ರವೇಶ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದು ಮತ್ತು ನಿಯಂತ್ರಿಸಬಹುದು. ಪರಿಶೀಲಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 43963afc6b04..c670af28db09 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"모나크"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"쿼토"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"풀스캡"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"지정되지 않은 세로 방향"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"지정되지 않은 가로 방향"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"취소됨"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"관리자에 의해 업데이트되었습니다."</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"관리자에 의해 삭제되었습니다."</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"확인"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"절전 모드는 어두운 테마를 사용 설정하고 백그라운드 활동, 일부 시각 효과, 특정 기능을 제한하거나 사용 중지합니다.\n\n"<annotation id="url">"자세히 알아보기"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"절전 모드는 어두운 테마를 사용 설정하고 백그라운드 활동, 일부 시각 효과, 특정 기능을 제한하거나 사용 중지합니다."</string> <string name="data_saver_description" msgid="4995164271550590517">"데이터 사용량을 줄이기 위해 데이터 절약 모드는 일부 앱이 백그라운드에서 데이터를 전송하거나 수신하지 못하도록 합니다. 현재 사용 중인 앱에서 데이터에 액세스할 수 있지만 빈도가 줄어듭니다. 예를 들면, 이미지를 탭하기 전에는 이미지가 표시되지 않습니다."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"데이터 절약 모드를 사용 설정하시겠습니까?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"사용 설정"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"이 알림의 중요도가 무음으로 하향되었습니다. 의견을 보내려면 탭하세요."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"이전에 이 알림의 중요도는 더 높았습니다. 의견을 보내려면 탭하세요."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"이전에 이 알림의 중요도는 더 낮았습니다. 의견을 보내려면 탭하세요."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"개선된 알림 기능 사용해 보기"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"추천 작업, 답장 등을 계속 받으려면 개선된 알림 기능을 사용 설정하세요. Android 적응형 알림은 더 이상 지원되지 않습니다."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"사용 설정"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"나중에"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"개선된 알림"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"이제 개선된 알림을 통해 추천 작업과 답장이 제공됩니다. Android 적응형 알림은 더 이상 지원되지 않습니다."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"확인"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"사용 중지"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"자세히 알아보기"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"개선된 알림 기능은 연락처 이름과 메시지 등 개인 정보가 포함된 모든 알림 내용을 읽어줍니다. 알림을 닫거나 알림에 표시되는 버튼 관련 작업(예: 전화 받기)을 실행할 수도 있습니다.\n\n또한 이 기능은 우선순위 모드를 사용 또는 사용 중지하고 관련 설정을 변경할 수 있습니다."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12에서는 Android 적응형 알림이 개선된 알림으로 대체됩니다. 이 기능은 추천 작업과 답장을 표시하고 알림을 정리해 줍니다.\n\n개선된 알림은 연락처 이름과 메시지 등 개인 정보가 포함된 알림 내용에 액세스할 수 있습니다. 이 기능은 전화 받기와 방해 금지 모드 제어와 같이 알림을 닫거나 알림을 처리할 수도 있습니다."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"루틴 모드 정보 알림"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"평소에 충전하는 시간 전에 배터리가 소진될 수 있습니다."</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"배터리 수명을 연장하기 위해 절전 모드가 활성화되었습니다."</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"애플리케이션 브랜드 이미지"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"접근성 설정 확인"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> 서비스가 내 화면을 보고 제어할 수 있습니다. 검토하려면 탭하세요."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index a2b199c0f37d..ba125403d50d 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch (184mm x 267mm)"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto (203mm x 254mm)"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap (203mm x 330mm)"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K (270mm x 390mm)"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K (195mm x 270mm)"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1 (102mm x 165mm)"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu (240mm x 322.1mm)"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2 (240mm x 332mm)"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4 (105mm x 235mm)"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"Ч"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Белгисиз, тикесинен"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Белгисиз, туурасынан"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Токтотулду"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Администраторуңуз жаңыртып койгон"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Администраторуңуз жок кылып салган"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ЖАРАЙТ"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Батареяны үнөмдөгүч режиминде Караңгы тема күйгүзүлүп, фондогу аракеттер, айрым визуалдык эффекттер жана белгилүү бир функциялар чектелип же өчүрүлөт.\n\n"<annotation id="url">"Кеңири маалымат"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Батареяны үнөмдөгүч режиминде Караңгы тема күйгүзүлүп, фондогу аракеттер, айрым визуалдык эффекттер жана белгилүү бир функциялар чектелип же өчүрүлөт."</string> <string name="data_saver_description" msgid="4995164271550590517">"Трафикти үнөмдөө режиминде айрым колдонмолор маалыматтарды фондо өткөрө алышпайт. Учурда сиз пайдаланып жаткан колдонмо маалыматтарды жөнөтүп/ала алат, бирок адаттагыдан азыраак өткөргөндүктөн, анын айрым функциялары талаптагыдай иштебей коюшу мүмкүн. Мисалы, сүрөттөр басылмайынча жүктөлбөйт."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Трафикти үнөмдөө режимин иштетесизби?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Күйгүзүү"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Бул билдирменин маанилүүлүгү Үнсүз болуп төмөндөтүлдү. Пикир билдирүү үчүн таптап коюңуз."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Бул билдирменин маанилүүлүгү жогорулатылды. Пикир билдирүү үчүн таптап коюңуз."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Бул билдирменин маанилүүлүгү төмөндөтүлдү. Пикир билдирүү үчүн таптап коюңуз."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Жакшыр-ган бил-ди байкап көрүү"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Сунушталган аракеттерди, жоопторду жана башка маалыматты ала берүү үчүн жакшыртылган билдирмелерди күйгүзүңүз. Android\'дин Ыңгайлаштырылуучу билдирмелери колдоого алынбай калды."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Күйгүзүү"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Азыр эмес"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Жакшыртылган билдирмелер"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Жакшыртылган билдирмелерде эми ыкчам аракеттер жана жооптор сунушталат. Android\'дин ыңгайлаштырылуучу билдирмелери колдоого алынбай калды."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Макул"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Өчүрүү"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Кененирээк"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Жакшыртылган билдирмелер бардык билдирмелердин мазмунун, ошондой эле байланыштардын аты-жөнү жана билдирүүлөр сыяктуу жеке маалыматты окуй алат. Мындан тышкары, билдирмелерди жаап же телефон чалууларына жооп берүү сыяктуу билдирмелердеги баскычтарды баса алат.\n\nБул функция Маанилүү жазышуулар режимин күйгүзүп же өчүрүп, ошондой эле анын жөндөөлөрүн өзгөртө алат."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 версиясында ыңгайлаштырылуучу билдирмелер жакшыртылган билдирмелерге алмаштырылды. Бул функция ыкчам аракеттерди жана жоопторду көрсөтүп, билдирмелериңизди иреттейт.\n\nЖакшыртылган билдирмелер бардык билдирмелердин мазмунун, ошондой эле байланыштардын аты-жөнү жана билдирүүлөрү сыяктуу жеке маалыматты көрө алат. Ошондой эле, бул функция билдирмелерди жаап, баскычтарын басып, телефон чалууларга жооп берип жана \"Тынчымды алба\" функциясын башкара алат."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Режимдин адаттагы билдирмеси"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарея кубаттоого чейин отуруп калышы мүмкүн"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Батареянын отуруп калбашы үчүн Батареяны үнөмдөгүч режими иштетилди"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Колдонмонун брендинин сүрөтү"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Кирүү мүмкүнчүлүгүнүн жөндөөлөрүн текшериңиз"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> экраныңызды көрүп, көзөмөлдөй алат. Көрүү үчүн таптап коюңуз."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 9426514e7425..5557b6068baa 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Unknown portrait"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Unknown landscape"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ຍົກເລີກແລ້ວ"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"ຖືກອັບໂຫລດໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ຖືກລຶບອອກໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ຕົກລົງ"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ ແລະ ຈຳກັດ ຫຼື ປິດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກທາງພາບຈຳນວນໜຶ່ງ ແລະ ຄຸນສົມບັດບາງຢ່າງ.\n\n"<annotation id="url">"ສຶກສາເພີ່ມເຕີມ"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ ແລະ ຈຳກັດ ຫຼື ປິດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກທາງພາບຈຳນວນໜຶ່ງ ແລະ ຄຸນສົມບັດບາງຢ່າງ."</string> <string name="data_saver_description" msgid="4995164271550590517">"ເພື່ອຊ່ວຍຫຼຸດຜ່ອນການນຳໃຊ້ຂໍ້ມູນ, ຕົວປະຢັດອິນເຕີເນັດຈະປ້ອງກັນບໍ່ໃຫ້ບາງແອັບສົ່ງ ຫຼື ຮັບຂໍ້ມູນໃນພື້ນຫຼັງ. ແອັບໃດໜຶ່ງທີ່ທ່ານກຳລັງໃຊ້ຢູ່ຈະສາມາດເຂົ້າເຖິງຂໍ້ມູນໄດ້ ແຕ່ອາດເຂົ້າເຖິງໄດ້ຖີ່ໜ້ອຍລົງ. ນີ້ອາດໝາຍຄວາມວ່າ ຮູບພາບຕ່າງໆອາດບໍ່ສະແດງຈົນກວ່າທ່ານຈະແຕະໃສ່ກ່ອນ."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ເປີດຕົວປະຢັດອິນເຕີເນັດບໍ?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"ເປີດໃຊ້"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ການແຈ້ງເຕືອນນີ້ຖືກຫຼຸດລະດັບເປັນປິດສຽງແລ້ວ. ແຕະເພື່ອສົ່ງຄຳຕິຊົມ."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ການແຈ້ງເຕືອນນີ້ຖືກເລື່ອນລະດັບຂຶ້ນແລ້ວ. ແຕະເພື່ອສົ່ງຄຳຕິຊົມ."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ການແຈ້ງເຕືອນນີ້ຖືກຫຼຸດລະດັບລົງແລ້ວ. ແຕະເພື່ອສົ່ງຄຳຕິຊົມ."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"ລອງໃຊ້ການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນ"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"ກະລຸນາເປີດໃຊ້ການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນເພື່ອສືບຕໍ່ຮັບຄຳສັ່ງທີ່ແນະນຳ, ການຕອບກັບ ແລະ ອື່ນໆ. ບໍ່ຮອງຮັບການແຈ້ງເຕືອນແບບປັບຕົວໄດ້ຂອງ Android ອີກຕໍ່ໄປແລ້ວ."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ເປີດໃຊ້"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ບໍ່ຟ້າວເທື່ອ"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"ການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນ"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"ຕອນນີ້ຄຳສັ່ງ ແລະ ການຕອບກັບທີ່ແນະນຳແມ່ນສະໜອງໃຫ້ໂດຍການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນ. ບໍ່ຮອງຮັບການແຈ້ງເຕືອນແບບປັບຕົວໄດ້ຂອງ Android ອີກຕໍ່ໄປແລ້ວ."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ຕົກລົງ"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ປິດໄວ້"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ສຶກສາເພີ່ມເຕີມ"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"ການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນສາມາດອ່ານເນື້ອຫາການແຈ້ງເຕືອນທັງໝົດໄດ້, ຮວມທັງຂໍ້ມູນສ່ວນຕົວ ເຊັ່ນ: ຊື່ຜູ້ຕິດຕໍ່ ແລະ ຂໍ້ຄວາມຕ່າງໆ. ນອກຈາກນັ້ນ, ຄຸນສົມບັດນີ້ຍັງສາມາດປິດການແຈ້ງເຕືອນໄວ້ ຫຼື ໃຊ້ຄຳສັ່ງຕ່າງໆຢູ່ປຸ່ມໃນການແຈ້ງເຕືອນໄດ້ນຳ ເຊັ່ນ: ການຮັບສາຍໂທລະສັບ.\n\nຄຸນສົມບັດນີ້ສາມາດເປີດ ຫຼື ປິດໂໝດສຳຄັນ ແລະ ປ່ຽນການຕັ້ງຄ່າທີ່ກ່ຽວຂ້ອງໄດ້ນຳ."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"ການແຈ້ງເຕືອນແບບປັບຕົວໄດ້ຂອງ Android ຖືກແທນທີ່ດ້ວຍການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນໃນ Android 12 ແລ້ວ. ຄຸນສົມບັດນີ້ສະແດງຄຳສັ່ງ ແລະ ການຕອບກັບທີ່ແນະນຳ ແລະ ຈັດລະບຽບການແຈ້ງເຕືອນຂອງທ່ານ.\n\nການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນສາມາດເຂົ້າເຖິງເນື້ອຫາການແຈ້ງເຕືອນໄດ້, ຮວມທັງຂໍ້ມູນສ່ວນຕົວ ເຊັ່ນ: ຊື່ຜູ້ຕິດຕໍ່ ແລະ ຂໍ້ຄວາມ. ຄຸນສົມບັດນີ້ສາມາດປິດ ຫຼື ຕອບກັບຫາການແຈ້ງເຕືອນໄດ້ນຳ ເຊັ່ນ: ການຮັບສາຍໂທລະສັບ ແລະ ການຄວບຄຸມໂໝດຫ້າມລົບກວນ."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ການແຈ້ງເຕືອນຂໍ້ມູນໂໝດກິດຈະວັດປະຈຳວັນ"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ແບັດເຕີຣີອາດໝົດກ່ອນການສາກຕາມປົກກະຕິ"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ເປີດຕົວປະຢັດແບັດເຕີຣີເພື່ອຂະຫຍາຍອາຍຸແບັດເຕີຣີ"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ຮູບແບຣນແອັບພລິເຄຊັນ"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"ກວດສອບການຕັ້ງຄ່າການເຂົ້າເຖິງ"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ສາມາດເບິ່ງ ແລະ ຄວບຄຸມໜ້າຈໍຂອງທ່ານໄດ້. ແຕະເພື່ອກວດສອບ."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index b6f6975efac4..26fd0ab33709 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1817,28 +1817,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1875,8 +1864,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Nežinomas stačias"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Nežinomas gulsčias"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Atšaukta"</string> @@ -1922,10 +1910,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Atnaujino administratorius"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Ištrynė administratorius"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Gerai"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Akumuliatoriaus tausojimo priemonė įjungia tamsiąją temą ir apriboja arba išjungia veiklą fone, kai kuriuos vaizdinius efektus bei tam tikras funkcijas.\n\n"<annotation id="url">"Sužinokite daugiau"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Akumuliatoriaus tausojimo priemonė įjungia tamsiąją temą ir apriboja arba išjungia veiklą fone, kai kuriuos vaizdinius efektus bei tam tikras funkcijas."</string> <string name="data_saver_description" msgid="4995164271550590517">"Kad padėtų sumažinti duomenų naudojimą, Duomenų taupymo priemonė neleidžia kai kurioms programoms siųsti ar gauti duomenų fone. Šiuo metu naudojama programa gali pasiekti duomenis, bet tai bus daroma rečiau. Tai gali reikšti, kad, pvz., vaizdai nebus pateikiami, jei jų nepaliesite."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Įj. Duomenų taupymo priemonę?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Įjungti"</string> @@ -2165,12 +2151,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Šio pranešimo svarba sumažinta iki begarsio lygio. Palieskite, kad pateiktumėte atsiliepimą."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Šio pranešimo svarba padidinta. Palieskite, kad pateiktumėte atsiliepimą."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Šio pranešimo svarba sumažinta. Palieskite, kad pateiktumėte atsiliepimą."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Išb. patobulintus pranešimus"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Norėdami toliau gauti siūlomus veiksmus, atsakymus ir daugiau, įjunkite patobulintus pranešimus. „Android“ prisitaikantys pranešimai nebepalaikomi."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Įjungti"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ne dabar"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Patobulinti pranešimai"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Siūlomi veiksmai ir atsakymai dabar teikiami patobulintais pranešimais. „Android“ prisitaikantys pranešimai nebepalaikomi."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Gerai"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Išjungti"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Sužinokite daugiau"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Patobulintų pranešimų funkcija gali skaityti visų pranešimų turinį, įskaitant asmens informaciją (pvz., kontaktų vardus ir pranešimus). Ši funkcija taip pat gali atsisakyti pranešimų ar imtis veiksmų su pranešimuose esančiais mygtukais, pvz., atsakyti į telefono skambučius.\n\nBe to, ši funkcija gali įjungti arba išjungti svarbiausių pokalbių režimą ir pakeisti susijusius nustatymus."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"12 versijos „Android“ patobulinti pranešimai pakeitė „Android“ prisitaikančius pranešimus. Ši funkcija rodo siūlomus veiksmus bei atsakymus ir tvarko jūsų pranešimus.\n\nPatobulintų pranešimų funkcija gali pasiekti pranešimų turinį, įskaitant asmens informaciją (pvz., kontaktų vardus ir pranešimus). Ši funkcija taip pat gali atsisakyti pranešimų arba į juos atsakyti, pvz., atsakyti į telefono skambučius ir valdyti netrukdymo režimą."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Veiksmų sekos režimo informacijos pranešimas"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumuliatoriaus energija gali išsekti prieš įprastą įkrovimą"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Akumuliatoriaus tausojimo priemonė suaktyvinta, kad akumuliatorius veiktų ilgiau"</string> @@ -2369,4 +2355,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Programos prekės ženklo vaizdas"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Patikrinkite prieigos nustatymus"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"„<xliff:g id="SERVICE_NAME">%s</xliff:g>“ gali peržiūrėti ir valdyti jūsų ekraną. Palieskite ir peržiūrėkite."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 70b37bd2c27f..6e09a6dafc11 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1795,28 +1795,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1853,8 +1842,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Nezināma izmēra portrets"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Nezināma izmēra ainava"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Atcelts"</string> @@ -1899,10 +1887,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Atjaunināja administrators"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Dzēsa administrators"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Labi"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs, kā arī tiek ierobežotas vai izslēgtas darbības fonā, daži vizuālie efekti un funkcijas.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs, kā arī tiek ierobežotas vai izslēgtas darbības fonā, daži vizuālie efekti un funkcijas."</string> <string name="data_saver_description" msgid="4995164271550590517">"Lai samazinātu datu lietojumu, datu lietojuma samazinātājs neļauj dažām lietotnēm fonā nosūtīt vai saņemt datus. Lietotne, kuru pašlaik izmantojat, var piekļūt datiem, bet, iespējams, piekļūs tiem retāk (piemēram, attēli tiks parādīti tikai tad, kad tiem pieskarsieties)."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Vai ieslēgt datu lietojuma samazinātāju?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Ieslēgt"</string> @@ -2132,12 +2118,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Šī paziņojuma svarīgums tika pazemināts, un paziņojums tiks rādīts bez skaņas. Lai sniegtu atsauksmes, pieskarieties."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Šī paziņojuma rangs tika paaugstināts. Lai sniegtu atsauksmes, pieskarieties."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Šī paziņojuma rangs tika pazemināts. Lai sniegtu atsauksmes, pieskarieties."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Uzlabotie paziņojumi"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Lai arī turpmāk saņemtu darbību un atbilžu ieteikumus un citu saturu, ieslēdziet uzlabotos paziņojumus. Android adaptīvie paziņojumi vairs netiek atbalstīti."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Ieslēgt"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Vēlāk"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Uzlabotie paziņojumi"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Tagad ieteiktās darbības un atbildes nodrošina funkcija Uzlabotie paziņojumi. Android adaptīvie paziņojumi vairs netiek atbalstīti."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Labi"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Izslēgt"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Uzzināt vairāk"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Funkcija “Uzlabotie paziņojumi” var lasīt visu paziņojumu saturu, tostarp personas informāciju, piemēram, kontaktpersonu vārdus un ziņojumus. Šī funkcija var arī noraidīt paziņojumus un izmantot paziņojumos esošās pogas darbību veikšanai, piemēram, atbildēt uz tālruņa zvaniem.\n\nTurklāt šī funkcija var ieslēgt un izslēgt režīmu Prioritāte un mainīt ar to saistītos iestatījumus."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 versijā Android adaptīvos paziņojumus aizstāja funkcija “Uzlabotie paziņojumi”. Šī funkcija parāda ieteiktās darbības un atbildes, kā arī kārto jūsu paziņojumus.\n\nFunkcija “Uzlabotie paziņojumi” var piekļūt paziņojumu saturam, tostarp personas informācijai, piemēram, kontaktpersonu vārdiem un ziņojumiem. Šī funkcija var arī noraidīt paziņojumus vai atbildēt uz tiem, piemēram, atbildēt uz tālruņa zvaniem vai pārvaldīt funkciju Netraucēt."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informatīvs paziņojums par akumulatoru"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumulators var izlādēties pirms parastā uzlādes laika"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Aktivizēts akumulatora enerģijas taupīšanas režīms, lai palielinātu akumulatora darbības ilgumu"</string> @@ -2335,4 +2321,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Lietojumprogrammas zīmola attēls"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Pārbaudiet piekļuves iestatījumus"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"Pakalpojums <xliff:g id="SERVICE_NAME">%s</xliff:g> var skatīt un kontrolēt jūsu ekrānu. Pieskarieties, lai to pārskatītu."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index df0afb0270cd..4d6b252be48a 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Непознат портрет"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Непознат пејзаж"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Откажано"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирано од администраторот"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Избришано од администраторот"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Во ред"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"„Штедачот на батерија“ ја вклучува темната тема и ги ограничува или исклучува активноста во заднина, некои визуелни ефекти и одредени функции.\n\n"<annotation id="url">"Дознајте повеќе"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"„Штедачот на батерија“ ја вклучува темната тема и ги ограничува или исклучува активноста во заднина, некои визуелни ефекти и одредени функции."</string> <string name="data_saver_description" msgid="4995164271550590517">"За да се намали користењето интернет, „Штедачот на интернет“ спречува дел од апликациите да испраќаат или да примаат податоци во заднина. Одредена апликација што ја користите ќе може да користи интернет, но можеби тоа ќе го прави поретко. Ова значи, на пример, дека сликите нема да се прикажуваат додека не ги допрете."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Да се вклучи „Штедач на интернет“?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Вклучи"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Приоритетноста на известувањево е намалена на „Тивко“. Допрете за да дадете повратни информации."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Известувањево е рангирано повисоко. Допрете за да дадете повратни информации."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Известувањево е рангирано пониско. Допрете за да дадете повратни информации."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Пробај „Подобрени известувања“"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Вклучете ги „Подобрените известувања“ за да продолжите да добивате предлози за дејства, одговори и слично. „Приспособливите известувања на Android“ веќе не се достапни."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Вклучи"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не сега"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Подобрени известувања"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"„Подобрените известувања“ сега ги даваат предложените дејства и одговорите. „Приспособливите известувања на Android“ веќе не се достапни."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Во ред"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Исклучи"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Дознајте повеќе"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"„Подобрените известувања“ може да ги читаат сите содржини од известувањата, вклучително и личните податоци, како што се имињата на контактите и пораките. Функцијава ќе може и да отфрла известувања или да ги користи копчињата во известувањата, како на пр., да одговара на телефонски повици.\n\nФункцијава може и да го вклучува или исклучува „Приоритетниот режим“ и да ги менува поврзаните поставки."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"„Подобрените известувања“ ги заменија „Приспособливите известувања на Android“ во Android 12. Оваа функција прикажува предложени дејства и одговори и ги организира вашите известувања.\n\n„Подобрените известувања“ може да пристапат до содржините од известувањата, вклучително и личните податоци, како што се имињата на контактите и пораките. Функцијава може и да отфрла или одговара на известувања, како на пример, одговарање телефонски повици и контролирање на „Не вознемирувај“."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Известување за информации за режимот за рутини"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батеријата може да се потроши пред вообичаеното време за полнење"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Активиран е „Штедачот на батерија“ за да се продолжи траењето на батеријата"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Слика за брендирање на апликацијата"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Проверете ги поставките за пристап"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> може да го прегледува и контролира вашиот екран. Допрете за да прегледате."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index d479d30093ca..a8bda14294cd 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"മൊണാർക്ക്"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"ക്വാർട്ടോ"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"ഫൂൾസ്കെയ്പ്പ്"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"കഹു"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"അജ്ഞാത പോർട്രെയ്റ്റ്"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"അജ്ഞാത ലാൻഡ്സ്കെയ്പ്പ്"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"റദ്ദാക്കി"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"നിങ്ങളുടെ അഡ്മിൻ അപ്ഡേറ്റ് ചെയ്യുന്നത്"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"നിങ്ങളുടെ അഡ്മിൻ ഇല്ലാതാക്കുന്നത്"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ശരി"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ബാറ്ററി ലാഭിക്കൽ ഡാർക്ക് തീം ഓണാക്കുന്നു, കൂടാതെ പശ്ചാത്തല ആക്റ്റിവിറ്റി, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, ചില ഫീച്ചറുകൾ എന്നിവ പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു.\n\n"<annotation id="url">"കൂടുതലറിയുക"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"ബാറ്ററി ലാഭിക്കൽ ഡാർക്ക് തീം ഓണാക്കുന്നു, കൂടാതെ പശ്ചാത്തല ആക്റ്റിവിറ്റി, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, ചില ഫീച്ചറുകൾ എന്നിവ പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string> <string name="data_saver_description" msgid="4995164271550590517">"ഡാറ്റാ ഉപയോഗം കുറയ്ക്കാൻ സഹായിക്കുന്നതിനായി പശ്ചാത്തലത്തിൽ ഡാറ്റ അയയ്ക്കുകയോ സ്വീകരിക്കുകയോ ചെയ്യുന്നതിൽ നിന്ന് ചില ആപ്പുകളെ ഡാറ്റാ സേവർ തടയുന്നു. നിങ്ങൾ നിലവിൽ ഉപയോഗിക്കുന്ന ഒരു ആപ്പിന് ഡാറ്റ ആക്സസ് ചെയ്യാനാകും, എന്നാൽ വല്ലപ്പോഴും മാത്രമെ സംഭവിക്കുന്നുള്ളു. ഇതിനർത്ഥം, ഉദാഹരണമായി നിങ്ങൾ ടാപ്പ് ചെയ്യുന്നത് വരെ ചിത്രങ്ങൾ പ്രദർശിപ്പിക്കുകയില്ല എന്നാണ്."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ഡാറ്റ സേവർ ഓണാക്കണോ?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"ഓണാക്കുക"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ഈ അറിയിപ്പിനെ നിശബ്ദമാക്കി തരം താഴ്ത്തി. ഫീഡ്ബാക്ക് നൽകാൻ ടാപ്പ് ചെയ്യുക."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ഈ അറിയിപ്പിന് ഉയർന്ന റാങ്ക് നൽകി. ഫീഡ്ബാക്ക് നൽകാൻ ടാപ്പ് ചെയ്യുക."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ഈ അറിയിപ്പിന് താഴ്ന്ന റാങ്ക് നൽകി. ഫീഡ്ബാക്ക് നൽകാൻ ടാപ്പ് ചെയ്യുക."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"മെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾ പരീക്ഷിക്കൂ"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"നിർദ്ദേശിച്ച പ്രവർത്തനങ്ങളും മറുപടികളും മറ്റും ലഭിക്കുന്നത് തുടരാൻ, മെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾ ഓണാക്കുക. Android അഡാപ്റ്റീവ് അറിയിപ്പുകൾക്ക് ഇനി പിന്തുണയില്ല."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ഓണാക്കുക"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ഇപ്പോൾ വേണ്ട"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"മെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾ"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"നിർദ്ദേശിക്കുന്ന പ്രവർത്തനങ്ങളും മറുപടികളും, \'മെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾ\' ഫീച്ചറാണ് ഇപ്പോൾ നൽകുന്നത്. Android അഡാപ്റ്റീവ് അറിയിപ്പുകൾക്ക് ഇനി പിന്തുണയില്ല."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ശരി"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ഓഫാക്കുക"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"കൂടുതലറിയുക"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"മെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾക്ക്, കോൺടാക്റ്റ് പേരുകളും സന്ദേശങ്ങളും പോലുള്ള വ്യക്തിപരമായ വിവരങ്ങൾ ഉൾപ്പെടെ എല്ലാ അറിയിപ്പ് ഉള്ളടക്കവും വായിക്കാനാകും. അറിയിപ്പുകൾ ഡിസ്മിസ് ചെയ്യാനോ ഫോൺ കോളുകൾക്ക് മറുപടി നൽകുന്നത് പോലെ അറിയിപ്പുകളിലെ ബട്ടണുകളിൽ നടപടിയെടുക്കാനോ ഈ ഫീച്ചറിന് കഴിയും.\n\nമുൻഗണനാ മോഡ് ഓണാക്കാനോ ഓഫാക്കാനോ ബന്ധപ്പെട്ട ക്രമീകരണം മാറ്റാനോ ഈ ഫീച്ചറിന് കഴിയും."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12-ൽ Android അഡാപ്റ്റീവ് അറിയിപ്പുകൾക്ക് പകരം മെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾ ഉൾപ്പെടുത്തിയിരിക്കുന്നു. നിർദ്ദേശിക്കുന്ന പ്രവർത്തനങ്ങളും മറുപടികളും കാണിക്കുന്നതിനൊപ്പം ഈ ഫീച്ചർ നിങ്ങളുടെ അറിയിപ്പുകൾ ഓർഗനൈസ് ചെയ്യുന്നു.\n\nമെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾക്ക്, കോൺടാക്റ്റ് പേരുകളും സന്ദേശങ്ങളും പോലുള്ള വ്യക്തിപരമായ വിവരങ്ങൾ ഉൾപ്പെടെയുള്ള അറിയിപ്പ് ഉള്ളടക്കം ആക്സസ് ചെയ്യാനാകും. ഫോൺ കോളുകൾക്ക് മറുപടി നൽകുക, \'ശല്യപ്പെടുത്തരുത്\' നിയന്ത്രിക്കുക എന്നിവ പോലെ, അറിയിപ്പുകൾ ഡിസ്മിസ് ചെയ്യാനും അവയ്ക്ക് മറുപടി നൽകാനും ഈ ഫീച്ചറിന് കഴിയും."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ദിനചര്യ മോഡ് വിവരത്തെ കുറിച്ചുള്ള അറിയിപ്പ്"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"സാധാരണയുള്ളതിലും നേരത്തെ ബാറ്ററിയുടെ ചാർജ് തീർന്നേക്കാം"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ബാറ്ററി ലൈഫ് വര്ദ്ധിപ്പിക്കാൻ, ബാറ്ററി ലാഭിക്കൽ സജീവമാക്കി"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"അപ്ലിക്കേഷൻ ബ്രാൻഡിംഗ് ഇമേജ്"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"ആക്സസ് ക്രമീകരണം പരിശോധിക്കുക"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> എന്നതിന് നിങ്ങളുടെ സ്ക്രീൻ കാണാനും നിയന്ത്രിക്കാനും കഴിയും. അവലോകനം ചെയ്യുന്നതിന് ടാപ്പ് ചെയ്യുക."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 6e8abd146ae5..99bd6743e544 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"Том"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Тодорхойгүй босоо цаас"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Тодорхойгүй хөндлөн цаас"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Цуцлагдсан"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Таны админ шинэчилсэн"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Таны админ устгасан"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагаа, зарим визуал эффект болон тодорхой онцлогуудийг хязгаарлаж эсвэл унтраана.\n\n"<annotation id="url">"Нэмэлт мэдээлэл авах"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагаа, зарим визуал эффект болон тодорхой онцлогуудийг хязгаарлаж эсвэл унтраана."</string> <string name="data_saver_description" msgid="4995164271550590517">"Дата ашиглалтыг багасгахын тулд дата хэмнэгч нь ар талд ажиллаж буй зарим апп-н өгөгдлийг илгээх болон авахаас сэргийлдэг. Таны одоогийн ашиглаж буй апп нь өгөгдөлд хандах боломжтой хэдий ч тогтмол хандахгүй. Энэ нь жишээлбэл зургийг товших хүртэл харагдахгүй гэсэн үг юм."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Дата хэмнэгчийг асаах уу?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Асаах"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Энэ мэдэгдлийг Чимээгүй болгож зэргийг нь бууруулсан байна. Санал хүсэлт өгөхийн тулд товшино уу."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Энэ мэдэгдлийг дээгүүр зэрэглэсэн байна. Санал хүсэлт өгөхийн тулд товшино уу."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Энэ мэдэгдлийг доогуур зэрэглэсэн байна. Санал хүсэлт өгөхийн тулд товшино уу."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Сайжруулсан мэдэгдлийг турших"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Санал болгосон үйлдэл, хариу болон илүү ихийг үргэлжлүүлэн авахын тулд сайжруулсан мэдэгдлийг асаана уу. Android-н Орчинтой тохирсон мэдэгдлийг дэмжихээ больсон байна."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Асаах"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Одоо биш"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Сайжруулсан мэдэгдэл"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Санал болгосон үйлдлүүд болон хариунуудыг одоо сайржуулсан мэдэгдлээр олгоно. Android-н Орчинтой тохирсон мэдэгдлийг цаашид дэмжихээ больсон."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Унтраах"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Нэмэлт мэдээлэл авах"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Сайжруулсан мэдэгдэл нь харилцагчийн нэр, мессеж зэрэг хувийн мэдээллийг оруулаад бүх мэдэгдлийн контентыг унших боломжтой. Энэ онцлог мөн мэдэгдлийг хаах эсвэл утасны дуудлагад хариулах гэх мэт мэдэгдэл дэх товчлуур дээр үйлдэл хийх боломжтой.\n\nЭнэ онцлог мөн Чухал горимыг асаах, унтраах болон холбогдох тохиргоог өөрчлөх боломжтой."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Сайжруулсан мэдэгдэл нь Android 12 дахь Android-н Орчинтой тохирсон мэдэгдлийг орлосон. Энэ онцлог нь санал болгосон үйлдлүүд болон хариунуудыг харуулж, таны мэдэгдлийг цэгцэлнэ.\n\nСайжруулсан мэдэгдэл нь харилцагчийн нэр, мессеж зэрэг хувийн мэдээллийг оруулаад мэдэгдлийн контентод хандах боломжтой. Энэ онцлог мөн утасны дуудлагад хариулах болон Бүү саад бол горимыг хянах зэргээр мэдэгдлийг хаах эсвэл түүнд хариулах боломжтой."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Хэвшлийн горимын мэдээллийн мэдэгдэл"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарей ихэвчлэн цэнэглэдэг хугацаанаас өмнө дуусаж болзошгүй"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Батарейн ажиллах хугацааг уртасгахын тулд Батарей хэмнэгчийг идэвхжүүллээ"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Аппын брэнд зураг"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Хандалтын тохиргоог шалгана уу"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> таны дэлгэцийг харах болон хянах боломжтой. Хянахын тулд товшино уу."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 44ca94e8abb8..b3b1d135c33f 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"अज्ञात पोट्रेट"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"अज्ञात लँडस्केप"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"रद्द केले"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"आपल्या प्रशासकाने अपडेट केले"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"आपल्या प्रशासकाने हटवले"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ओके"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट व ठरावीक वैशिष्ट्ये मर्यादित किंवा बंद करते.\n\n"<annotation id="url">"अधिक जाणून घ्या"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट व ठरावीक वैशिष्ट्ये मर्यादित किंवा बंद करते."</string> <string name="data_saver_description" msgid="4995164271550590517">"डेटाचा वापर कमी करण्यात मदत करण्यासाठी काही अॅप्सना बॅकग्राउंडमध्ये डेटा पाठवण्यास किंवा मिळवण्यास डेटा सर्व्हर प्रतिबंध करतो. तुम्ही सध्या वापरत असलेले अॅप डेटा अॅक्सेस करू शकते, पण तसे खूप कमी वेळा होते. याचाच अर्थ असा की, तुम्ही इमेजवर टॅप करेपर्यंत त्या डिस्प्ले होणार नाहीत असे होऊ शकते."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेव्हर सुरू करायचे?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"सुरू करा"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ही सूचना सायलंट करण्यात आली आहे. फीडबॅक देण्यासाठी टॅप करा."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"हा सूचनेला उच्च रँक करण्यात आले. फीडबॅक देण्यासाठी टॅप करा."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"या सूचनेला कमी रँक करण्यात आले. फीडबॅक देण्यासाठी टॅप करा."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"वर्धित सूचना वापरून पहा"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"सुचवलेल्या कृती, उत्तरे आणि आणखी बरेच काही मिळवत राहण्यासाठी, वर्धित सूचना सुरू करा. Android अॅडॅप्टिव्ह सूचना यांना आता सपोर्ट नाही."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"सुरू करा"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"आता नको"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"वर्धित सूचना"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"सुचवलेल्या कृती आणि उत्तरे आता वर्धित सूचनांद्वारे दिल्या जातात. Android अॅडॅप्टिव्ह सूचना यांना आता सपोर्ट नाही."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ओके"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"बंद करा"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"अधिक जाणून घ्या"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"संपर्कांची नावे आणि मेसेज यांसारख्या वैयक्तिक माहितीच्या समावेशासह वर्धित सूचना या सर्व सूचनांचा आशय वाचू शकतात. हे वैशिष्ट्य सूचना डिसमिस करू शकते किंवा फोन कॉलना उत्तर देण्यासारख्या सूचनांमधील बटणवर कृतीदेखील करू शकते.\n\nहे वैशिष्ट्य प्राधान्य मोड सुरू किंवा बंद करू शकते आणि संबंधित सेटिंग्जदेखील बदलू शकते."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 मधील Android अॅडॅप्टिव्ह सूचना यांना आता वर्धित सूचनांनी बदलले आहे. हे वैशिष्ट्य सुचवलेल्या कृती आणि उत्तरे दाखवते व तुमच्या सूचना व्यवस्थापित करते.\n\nवर्धित सूचना या संपर्कांची नावे आणि मेसेज यांसारख्या वैयक्तिक माहितीसह सर्व सूचनांचा आशय अॅक्सेस करू शकतात. हे वैशिष्ट्य फोन कॉलना उत्तर देणे आणि व्यत्यय आणू नका नियंत्रित करणे यांसारख्या कृती करून सूचना डिसमिस करू शकते किंवा त्यांना प्रतिसाद देऊ शकते."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"दिनक्रम मोडची माहिती सूचना"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"चार्जिंगची सामान्य पातळी गाठेपर्यंत कदाचित बॅटरी संपू शकते"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"बॅटरी लाइफ वाढवण्यासाठी बॅटरी सेव्हर सुरू केला आहे"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"अॅप्लिकेशन ब्रॅंडिंग इमेज"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"अॅक्सेसशी संबंधित सेटिंग्ज तपासा"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> हे तुमची स्क्रीन पाहू शकते आणि नियंत्रित करू शकते. परीक्षण करण्यासाठी टॅप करा."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index ddb4816fd942..937b31f40386 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarki"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Kertas kajang"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Potret tidak diketahui"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Landskap tidak diketahui"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Dibatalkan"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Dikemas kini oleh pentadbir anda"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Dipadamkan oleh pentadbir anda"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Penjimat Bateri menghidupkan tema Gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual dan ciri tertentu.\n\n"<annotation id="url">"Ketahui lebih lanjut"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Penjimat Bateri menghidupkan tema Gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual dan ciri tertentu."</string> <string name="data_saver_description" msgid="4995164271550590517">"Untuk membantu penggunaan data dikurangkan, Penjimat Data menghalang sesetengah apl daripada menghantar atau menerima data di latar. Apl yang sedang digunakan boleh mengakses data tetapi mungkin tidak secara kerap. Perkara ini mungkin bermaksud bahawa imej tidak dipaparkan sehingga anda mengetik pada imej itu, contohnya."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Hidupkan Penjimat Data?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Hidupkan"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Pemberitahuan ini telah diturun taraf kepada Senyap. Ketik untuk memberikan maklum balas."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Pemberitahuan ini berada di kedudukan lebih tinggi. Ketik untuk memberikan maklum balas."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Pemberitahuan ini berada di kedudukan lebih rendah. Ketik untuk memberikan maklum balas."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Cuba pemberitahuan dipertingkatkan"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Untuk terus mendapatkan tindakan yang dicadangkan, balasan dan banyak lagi, hidupkan pemberitahuan yang dipertingkatkan. Pemberitahuan Boleh Suai Android tidak disokong lagi."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Hidupkan"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Bukan sekarang"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Pemberitahuan dipertingkatkan"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Tindakan dan balasan yang dicadangkan kini disediakan oleh pemberitahuan yang dipertingkatkan. Pemberitahuan Boleh Suai Android tidak disokong lagi."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Matikan"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Ketahui lebih lanjut"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Pemberitahuan yang dipertingkatkan dapat membaca semua kandungan pemberitahuan, termasuk maklumat peribadi seperti nama kenalan dan mesej. Ciri ini juga dapat mengetepikan pemberitahuan atau mengambil tindakan pada butang dalam pemberitahuan, seperti menjawab panggilan telefon.\n\nCiri ini juga dapat menghidupkan atau mematikan mod Keutamaan dan menukar tetapan yang berkaitan."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Pemberitahuan yang dipertingkatkan menggantikan Pemberitahuan Boleh Suai Android dalam Android 12. Ciri ini menunjukkan tindakan dan balasan yang dicadangkan, serta mengatur pemberitahuan anda.\n\nPemberitahuan yang dipertingkatkan dapat mengakses kandungan pemberitahuan, termasuk maklumat peribadi seperti nama kenalan dan mesej. Ciri ini juga dapat mengetepikan atau membalas pemberitahuan, seperti menjawab panggilan telefon dan mengawal Jangan Ganggu."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Pemberitahuan maklumat Mod Rutin"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateri mungkin habis sebelum pengecasan biasa"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Penjimat Bateri diaktifkan untuk memanjangkan hayat bateri"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imej jenama aplikasi"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Semak tetapan akses"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> boleh melihat dan mengawal skrin anda. Ketik untuk membuat semakan."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index d1575b917f86..983de0e8d998 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"မိုနာချ့်"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"ကွာတို"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"ဖူးစကဒ်"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"အာအိုစီ ၈ကေ"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"အာအိုစီ ၁၆ကေ"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"ပီအာစီ ၁"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"ကဟူ"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"ကဟူ၂"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"ယူ၄"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"ဒေါင်လိုက် အရွယ်မသိ"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"အလျားလိုက် အရွယ်မသိ"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ဖျက်သိမ်းလိုက်ပြီး"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"သင်၏ စီမံခန့်ခွဲသူက အပ်ဒိတ်လုပ်ထားသည်"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"သင်၏ စီမံခန့်ခွဲသူက ဖျက်လိုက်ပါပြီ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ကို ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် ဝန်ဆောင်မှုအချို့ကို ကန့်သတ်သည် သို့မဟုတ် ပိတ်သည်။\n\n"<annotation id="url">"ပိုမိုလေ့လာရန်"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ကို ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် ဝန်ဆောင်မှုအချို့ကို ကန့်သတ်သည် သို့မဟုတ် ပိတ်သည်။"</string> <string name="data_saver_description" msgid="4995164271550590517">"ဒေတာအသုံးလျှော့ချနိုင်ရန်အတွက် အက်ပ်များကို နောက်ခံတွင် ဒေတာပို့ခြင်းနှင့် လက်ခံခြင်းမပြုရန် \'ဒေတာချွေတာမှု\' စနစ်က တားဆီးထားပါသည်။ ယခုအက်ပ်ဖြင့် ဒေတာအသုံးပြုနိုင်သော်လည်း အကြိမ်လျှော့၍သုံးရပါမည်။ ဥပမာ၊ သင်က မတို့မချင်း ပုံများပေါ်လာမည် မဟုတ်ပါ။"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ဒေတာချွေတာမှုစနစ် ဖွင့်မလား။"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"ဖွင့်ပါ"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ဤအကြောင်းကြားချက်ကို \'အသံတိတ်ခြင်း\' သို့ ပြန်ချိန်ညှိထားသည်။ အကြံပြုချက်ပေးရန် တို့ပါ။"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ဤအကြောင်းကြားချက်ကို အဆင့်တိုးထားသည်။ အကြံပြုချက်ပေးရန် တို့ပါ။"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ဤအကြောင်းကြားချက်ကို အဆင့်လျှော့ထားသည်။ အကြံပြုချက်ပေးရန် တို့ပါ။"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"အဆင့်မြင့် အကြောင်းကြားချက်များ စမ်းသုံးကြည့်ခြင်း"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"အကြံပြုထားသော လုပ်ဆောင်ချက်များ၊ ပြန်စာများ စသည်တို့ကို ဆက်လက်ရယူရန် အဆင့်မြင့် အကြောင်းကြားချက်များကို ဖွင့်ပါ။ ‘Android အလိုက်သင့် အကြောင်းကြားချက်များ’ ကို ပံ့ပိုးမထားတော့ပါ။"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ဖွင့်ရန်"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ယခုမလုပ်ပါ"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"အဆင့်မြင့် အကြောင်းကြားချက်များ"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"အကြံပြုထားသော လုပ်ဆောင်ချက်နှင့် ပြန်စာများကို အဆင့်မြင့် အကြောင်းကြားချက်များဖြင့် ယခု ပံ့ပိုးပေးသည်။ ‘Android အလိုက်သင့် အကြောင်းကြားချက်များ’ ကို ပံ့ပိုးမထားတော့ပါ။"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ပိတ်ရန်"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ပိုမိုလေ့လာရန်"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"အဆင့်မြင့် အကြောင်းကြားချက်များသည် အဆက်အသွယ်အမည်နှင့် မက်ဆေ့ဂျ်များကဲ့သို့ ကိုယ်ရေးကိုယ်တာအချက်လက်များ အပါအဝင် အကြောင်းကြားချက် အကြောင်းအရာအားလုံးကို ဖတ်နိုင်သည်။ ဤဝန်ဆောင်မှုသည် အကြောင်းကြားချက်များကို ပယ်ခြင်း (သို့) ဖုန်းခေါ်ဆိုမှုများ ဖြေခြင်းကဲ့သို့ အကြောင်းကြားချက်များရှိ ခလုတ်များ နှိပ်ခြင်းကိုလည်း ပြုလုပ်နိုင်သည်။\n\nဤဝန်ဆောင်မှုသည် ‘ဦးစားပေးမုဒ်’ ကို ဖွင့်ခြင်း (သို့) ပိတ်ခြင်း ပြုလုပ်နိုင်ပြီး ဆက်စပ်နေသော ဆက်တင်များကိုလည်း ပြောင်းနိုင်သည်။"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 တွင် ‘Android အလိုက်သင့် အကြောင်းကြားချက်များ’ ကို အဆင့်မြင့် အကြောင်းကြားချက်များဖြင့် အစားထိုးထားသည်။ ဤဝန်ဆောင်မှုက အကြံပြုထားသော လုပ်ဆောင်ချက်နှင့် ပြန်စာများကို ပြပေးပြီး သင်၏အကြောင်းကြားချက်များကို စီစဉ်ပေးသည်။\n\nအဆင့်မြင့် အကြောင်းကြားချက်များက အဆက်အသွယ်အမည်နှင့် မက်ဆေ့ဂျ်များကဲ့သို့ ကိုယ်ရေးကိုယ်တာအချက်လက်များ အပါအဝင် အကြောင်းကြားချက် အကြောင်းအရာကို သုံးနိုင်သည်။ ဤဝန်ဆောင်မှုက ဖုန်းခေါ်ဆိုမှုများ ဖြေခြင်းနှင့် ‘မနှောင့်ယှက်ရ’ ကို ထိန်းချုပ်ခြင်းကဲ့သို့ အကြောင်းကြားချက်များကို ပယ်နိုင်သည် (သို့) တုံ့ပြန်နိုင်သည်။"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ပုံမှန်မုဒ်အတွက် အချက်အလက်ပြသည့် အကြောင်းကြားချက်"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ပုံမှန်အားသွင်းမှုမပြုလုပ်မီ ဘက်ထရီကုန်သွားနိုင်သည်"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ဘက်ထရီသက်တမ်းကို တိုးမြှင့်ရန် \'ဘက်ထရီအားထိန်း\' စတင်ပြီးပါပြီ"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"အပလီကေးရှင်း ကုန်အမှတ်တံဆိပ်ပုံ"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"အသုံးပြုခွင့် ဆက်တင်များကို စစ်ဆေးပါ"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> က သင့်ဖန်သားပြင်ကို ကြည့်ရှုပြီး ထိန်းချုပ်နိုင်သည်။ ပြန်ကြည့်ရန် တို့ပါ။"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 3635fb02531c..20c49d51fe94 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Ukjent portrett"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Ukjent landskap"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Kansellert"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Oppdatert av administratoren din"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet av administratoren din"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Batterisparing slår på mørkt tema og begrenser eller slår av bakgrunnsaktivitet, enkelte visuelle effekter og noen funksjoner.\n\n"<annotation id="url">"Finn ut mer"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Batterisparing slår på mørkt tema og begrenser eller slår av bakgrunnsaktivitet, enkelte visuelle effekter og noen funksjoner."</string> <string name="data_saver_description" msgid="4995164271550590517">"Datasparing hindrer noen apper fra å sende og motta data i bakgrunnen, for å redusere dataforbruket. Aktive apper kan bruke data, men kanskje ikke så mye som ellers – for eksempel vises ikke bilder før du trykker på dem."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Vil du slå på Datasparing?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Slå på"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Dette varselet ble nedgradert til lydløst. Trykk for å gi tilbakemelding."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Dette varselet ble rangert høyere. Trykk for å gi tilbakemelding."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Dette varselet ble rangert lavere. Trykk for å gi tilbakemelding."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Prøv forbedrede varsler"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"For å fortsette å få foreslåtte handlinger, svar med mer, slå på forbedrede varsler. Tilpassede Android-varsler støttes ikke lenger."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Slå på"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ikke nå"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Forbedrede varsler"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Foreslåtte handlinger og svar leveres nå i forbedrede varsler. Tilpassede Android-varsler støttes ikke lenger."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Slå av"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Finn ut mer"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Forbedrede varsler kan lese alt varselinnhold, inkludert personopplysninger som kontaktnavn og meldinger. Denne funksjonen kan også avvise varsler eller bruke knapper i varsler, for eksempel for å svare på telefonanrop.\n\nDenne funksjonen kan også slå prioriteringsmodus på eller av og endre relaterte innstillinger."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Forbedrede varsler erstatter tilpassede Android-varsler i Android 12. Denne funksjonen viser foreslåtte handlinger og svar og organiserer varslene dine.\n\nForbedrede varsler har tilgang til varselinnhold, inkludert personopplysninger som kontaktnavn og meldinger. Funksjonen kan også avvise og svare på varsler, for eksempel svare på anrop og kontrollere «Ikke forstyrr»."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Varsel med informasjon om rutinemodus"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batteriet kan gå tomt før den vanlige ladingen"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterisparing er aktivert for å forlenge batterilevetiden"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Merkevareprofilen til appen"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Sjekk tilgangsinnstillingene"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> kan se og kontrollere skjermen. Trykk for å gjennomgå."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 90e0d24fa8ed..d4f308397c3a 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -246,7 +246,7 @@ <string name="global_action_lock" msgid="6949357274257655383">"स्क्रिन बन्द"</string> <string name="global_action_power_off" msgid="4404936470711393203">"बन्द गर्नुहोस्"</string> <string name="global_action_power_options" msgid="1185286119330160073">"पावर"</string> - <string name="global_action_restart" msgid="4678451019561687074">"पुनः सुरु गर्नुहोस्"</string> + <string name="global_action_restart" msgid="4678451019561687074">"रिस्टार्ट गर्नुहोस्"</string> <string name="global_action_emergency" msgid="1387617624177105088">"आपत्कालीन"</string> <string name="global_action_bug_report" msgid="5127867163044170003">"बग रिपोर्ट"</string> <string name="global_action_logout" msgid="6093581310002476511">"सत्रको अन्त्य गर्नुहोस्"</string> @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"मोनार्क"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"क्वार्टो"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"फुलस्केप"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super-B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"अज्ञात चित्र"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"अज्ञात परिदृश्य"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"रद्द गरियो"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"तपाईंका प्रशासकले अद्यावधिक गर्नुभएको"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"तपाईंका प्रशासकले मेट्नुभएको"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ठिक छ"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ब्याट्री सेभरले अँध्यारो थिम अन गर्छ र ब्याकग्राउन्डमा हुने क्रियाकलाप, केही भिजुअल इफेक्ट र निश्चित सुविधाहरू अफ गर्छ वा सीमित रूपमा मात्र चल्न दिन्छ।\n\n"<annotation id="url">"थप जान्नुहोस्"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"ब्याट्री सेभरले अँध्यारो थिम अन गर्छ र ब्याकग्राउन्डमा हुने क्रियाकलाप, केही भिजुअल इफेक्ट र निश्चित सुविधाहरू अफ गर्छ वा सीमित रूपमा मात्र चल्न दिन्छ।"</string> <string name="data_saver_description" msgid="4995164271550590517">"डेटा सेभरले डेटा खपत कम गर्न केही एपहरूलाई ब्याकग्राउन्डमा डेटा पठाउन वा प्राप्त गर्न दिँदैन। तपाईंले अहिले प्रयोग गरिरहनुभएको एपले सीमित रूपमा मात्र डेटा चलाउन पाउँछ। उदाहरणका लागि, तपाईंले फोटोमा ट्याप गर्नुभयो भने मात्र फोटो देखिन्छ नत्र देखिँदैन।"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेभर अन गर्ने हो?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"सक्रिय गर्नुहोस्"</string> @@ -2099,17 +2085,16 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"यस सूचनालाई कम महत्त्वपूर्ण ठानी यसका लागि साइलेन्ट मोड सेट गरिएको छ। प्रतिक्रिया दिन ट्याप गर्नुहोस्।"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"यस सूचनालाई धेरै महत्त्वपूर्ण सूचनाका रूपमा सेट गरिएको छ। प्रतिक्रिया दिन ट्याप गर्नुहोस्।"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"यस सूचनालाई कम महत्त्वपूर्ण सूचनाका रूपमा सेट गरिएको छ। प्रतिक्रिया दिन ट्याप गर्नुहोस्।"</string> - <!-- no translation found for nas_upgrade_notification_title (4224351129445073051) --> - <skip /> - <!-- no translation found for nas_upgrade_notification_content (7036860187157134706) --> + <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) --> <skip /> - <!-- no translation found for nas_upgrade_notification_enable_action (4823652531622744798) --> + <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) --> <skip /> - <!-- no translation found for nas_upgrade_notification_disable_action (7561210256700811433) --> + <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) --> <skip /> - <!-- no translation found for nas_upgrade_notification_learn_more_action (7011130656195423947) --> + <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) --> <skip /> - <!-- no translation found for nas_upgrade_notification_learn_more_content (6276343083934111208) --> + <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"थप जान्नुहोस्"</string> + <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) --> <skip /> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"दिनचर्या मोडको जानकारीमूलक सूचना"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"प्रायः चार्ज गर्ने समय हुनुभन्दा पहिले नै ब्याट्री सकिन सक्छ"</string> @@ -2307,4 +2292,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"एपको ब्रान्डिङ फोटो"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"हेराइ र नियन्त्रणसम्बन्धी सेटिङ जाँच्नुहोस्"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> तपाईंको स्क्रिन हेर्न र नियन्त्रण गर्न सक्छ। सेटिङ मिलाउन ट्याप गर्नुहोस्।"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index af56ee3f6571..f2533b3f8d85 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1108,8 +1108,8 @@ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> minuut geleden</item> </plurals> <plurals name="duration_hours_relative" formatted="false" msgid="420434788589102019"> - <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> uur geleden, </item> - <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> uur geleden, </item> + <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> uur geleden</item> + <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> uur geleden</item> </plurals> <plurals name="duration_days_relative" formatted="false" msgid="6056425878237482431"> <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> dagen geleden</item> @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Onbekend staand"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Onbekend liggend"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Geannuleerd"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Geüpdatet door je beheerder"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Verwijderd door je beheerder"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, sommige visuele effecten en bepaalde functies beperkt of uitgezet.\n\n"<annotation id="url">"Meer informatie"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, sommige visuele effecten en bepaalde functies beperkt of uitgezet."</string> <string name="data_saver_description" msgid="4995164271550590517">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens sturen of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden dan bijvoorbeeld niet weergegeven totdat je erop tikt."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Databesparing aanzetten?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Aanzetten"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Deze melding is verlaagd naar Stil. Tik om feedback te geven."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Deze melding is hoger geclassificeerd. Tik om feedback te geven."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Deze melding is lager geclassificeerd. Tik om feedback te geven."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Probeer verbeterde meldingen"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Activeer verbeterde meldingen om voorgestelde acties, antwoorden en meer te blijven ontvangen. Aanpasbare Android-meldingen worden niet meer ondersteund."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aanzetten"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Niet nu"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Verbeterde meldingen"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Voorgestelde acties en antwoorden worden nu geleverd via verbeterde meldingen. Aanpasbare Android-meldingen worden niet meer ondersteund."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Uitzetten"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Meer informatie"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Verbeterde meldingen kunnen alle meldingscontent lezen, waaronder persoonlijke informatie zoals contactnamen en berichten. Deze functie kan ook meldingen sluiten of acties uitvoeren voor knoppen in meldingen, zoals telefoongesprekken aannemen.\n\nDeze functie kan ook de prioriteitsmodus aan- of uitzetten en gerelateerde instellingen wijzigen."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"In Android 12 hebben verbeterde meldingen aanpasbare Android-meldingen vervangen. Deze functie laat voorgestelde acties en antwoorden zien en ordent je meldingen.\n\nVerbeterde meldingen hebben toegang tot meldingscontent, waaronder persoonlijke informatie zoals contactnamen en berichten. Deze functie kan ook meldingen sluiten of erop reageren, zoals telefoongesprekken aannemen en Niet storen beheren."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informatiemelding voor routinemodus"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"De batterij raakt mogelijk leeg voordat deze normaal gesproken wordt opgeladen"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterijbesparing is geactiveerd om de batterijduur te verlengen"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Merkafbeelding voor app"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Toegangsinstellingen checken"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> kan je scherm bekijken en bedienen. Tik om te checken."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 734a81e00069..5aa16e7e22de 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"ମୋନାର୍କ"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"କ୍ୱାର୍ଟୋ"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"ଅଜଣା ପୋର୍ଟ୍ରେଟ୍"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"ଅଜଣା ଲ୍ୟାଣ୍ଡସ୍କେପ୍"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ବାତିଲ୍ କରାଗଲା"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"ଆପଣଙ୍କ ଆଡମିନ୍ ଅପଡେଟ୍ କରିଛନ୍ତି"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ଆପଣଙ୍କ ଆଡମିନ୍ ଡିଲିଟ୍ କରିଛନ୍ତି"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ଠିକ୍ ଅଛି"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ବ୍ୟାଟେରୀ ସେଭର୍ ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ ଏବଂ ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ଇଫେକ୍ଟ ଏବଂ କିଛି ଫିଚରଗୁଡ଼ିକୁ ସୀମିତ କିମ୍ବା ବନ୍ଦ କରେ।\n\n"<annotation id="url">"ଅଧିକ ଜାଣନ୍ତୁ"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"ବ୍ୟାଟେରୀ ସେଭର୍ ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ ଏବଂ ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ଇଫେକ୍ଟ ଏବଂ କିଛି ଫିଚରଗୁଡ଼ିକୁ ସୀମିତ କିମ୍ବା ବନ୍ଦ କରେ।"</string> <string name="data_saver_description" msgid="4995164271550590517">"ଡାଟା ବ୍ୟବହାର କମ୍ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ, ଡାଟା ସେଭର୍ ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡରେ ଡାଟା ପଠାଇବା କିମ୍ବା ପ୍ରାପ୍ତ କରିବାକୁ କିଛି ଆପ୍କୁ ବାରଣ କରେ। ଆପଣ ବର୍ତ୍ତମାନ ବ୍ୟବହାର କରୁଥିବା ଆପ୍, ଡାଟା ଆକ୍ସେସ୍ କରିପାରେ, କିନ୍ତୁ ଏହା କମ୍ ଥର କରିପାରେ। ଏହାର ଅର୍ଥ ହୋଇପାରେ ଯେମିତି ଆପଣ ଇମେଜଗୁଡ଼ିକୁ ଟାପ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ସେଗୁଡ଼ିକ ଡିସପ୍ଲେ ହୁଏ ନାହିଁ।"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ଡାଟା ସେଭର୍ ଚାଲୁ କରିବେ?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"ଚାଲୁ କରନ୍ତୁ"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ଏହି ବିଜ୍ଞପ୍ତିକୁ ନୀରବ ଭାବେ ଡିମୋଟ୍ କରାଯାଇଛି। ମତାମତ ପ୍ରଦାନ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ଏହି ବିଜ୍ଞପ୍ତିର ରେଙ୍କ ଉପରକୁ କରାଯାଇଛି। ମତାମତ ପ୍ରଦାନ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ଏହି ବିଜ୍ଞପ୍ତିର ରେଙ୍କ ତଳକୁ କରାଯାଇଛି। ମତାମତ ପ୍ରଦାନ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"ଉନ୍ନତ ବିଜ୍ଞପ୍ତି ବ୍ୟବହାରକରି ଦେଖ"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"ପ୍ରସ୍ତାବିତ କାର୍ଯ୍ୟ, ପ୍ରତ୍ୟୁତ୍ତର ଏବଂ ଆହୁରି ଅନେକ କିଛି ପାଇବା ଜାରି ରଖିବାକୁ, ଉନ୍ନତ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଚାଲୁ କରନ୍ତୁ। Android ଆଡେପ୍ଟିଭ୍ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଆଉ ସମର୍ଥିତ ନୁହେଁ।"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ଚାଲୁ କରନ୍ତୁ"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ବର୍ତ୍ତମାନ ନୁହେଁ"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"ଉନ୍ନତ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"ପ୍ରସ୍ତାବିତ କାର୍ଯ୍ୟ ଏବଂ ପ୍ରତ୍ୟୁତ୍ତରଗୁଡ଼ିକ ବର୍ତ୍ତମାନ ଉନ୍ନତ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ମାଧ୍ୟମରେ ପ୍ରଦାନ କରାଯାଉଛି। Android ଆଡେପ୍ଟିଭ୍ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଆଉ ସମର୍ଥିତ ନୁହେଁ।"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ଠିକ୍ ଅଛି"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ବନ୍ଦ କରନ୍ତୁ"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ଅଧିକ ଜାଣନ୍ତୁ"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"ଉନ୍ନତ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଯୋଗାଯୋଗ ନାମ ଏବଂ ମେସେଜଗୁଡ଼ିକ ପରି ବ୍ୟକ୍ତିଗତ ସୂଚନା ସମେତ ସମସ୍ତ ବିଜ୍ଞପ୍ତି ବିଷୟବସ୍ତୁକୁ ପଢ଼ିପାରିବ। ଏହି ଫିଚର୍ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଖାରଜ କରିପାରିବ କିମ୍ବା ଫୋନ୍ କଲଗୁଡ଼ିକର ଉତ୍ତର ଦେବା ପରି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକରେ ଥିବା ବଟନଗୁଡ଼ିକ ଉପରେ ପଦକ୍ଷେପ ମଧ୍ୟ ନେଇପାରିବ।\n\nଏହି ଫିଚର୍ ପ୍ରାଥମିକତା ମୋଡକୁ ଚାଲୁ କିମ୍ବା ବନ୍ଦ କରିପାରିବ ଏବଂ ସମ୍ବନ୍ଧିତ ସେଟିଂସକୁ ପରିବର୍ତ୍ତନ ମଧ୍ୟ କରିପାରିବ।"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12ରେ Android ଆଡେପ୍ଟିଭ୍ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଉନ୍ନତ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକରେ ପରିବର୍ତ୍ତନ କରାଯାଇଛି। ଏହି ଫିଚର୍ ପ୍ରସ୍ତାବିତ କାର୍ଯ୍ୟ ଏବଂ ପ୍ରତ୍ୟୁତ୍ତରଗୁଡ଼ିକୁ ଦେଖାଏ ଏବଂ ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବ୍ୟବସ୍ଥିତ କରେ।\n\nଉନ୍ନତ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଯୋଗାଯୋଗ ନାମ ଏବଂ ମେସେଜଗୁଡ଼ିକ ପରି ବ୍ୟକ୍ତିଗତ ସୂଚନା ସମେତ ବିଜ୍ଞପ୍ତିର ବିଷୟବସ୍ତୁକୁ ଆକ୍ସେସ୍ କରିପାରିବ। ଏହି ଫିଚର୍ ଫୋନ୍ କଲଗୁଡ଼ିକର ଉତ୍ତର ଦେବା ଏବଂ \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\'କୁ ନିୟନ୍ତ୍ରଣ କରିବା ପରି, ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ମଧ୍ୟ ଖାରଜ କରିପାରିବ କିମ୍ବା ସେଗୁଡ଼ିକର ଉତ୍ତର ଦେଇପାରିବ।"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ନିୟମିତ ମୋଡ୍ ସୂଚନା ବିଜ୍ଞପ୍ତି"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ସାଧାରଣ ଭାବରେ ଚାର୍ଜ୍ କରିବା ପୂର୍ବରୁ ବ୍ୟାଟେରୀ ସରିଯାଇପାରେ"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ବ୍ୟାଟେରୀର ସମୟକୁ ବଢ଼ାଇବା ପାଇଁ ବ୍ୟଟେରୀ ସେଭର୍କୁ କାର୍ଯ୍ୟକାରୀ କରାଯାଇଛି"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ଆପ୍ଲିକେସନ୍ ବ୍ରାଣ୍ଡିଂ ଛବି"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"ଆକ୍ସେସ୍ ସେଟିଂସକୁ ଯାଞ୍ଚ କରନ୍ତୁ"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ଆପଣଙ୍କ ସ୍କ୍ରିନକୁ ଦେଖିପାରିବ ଏବଂ ନିୟନ୍ତ୍ରଣ କରିପାରିବ। ସମୀକ୍ଷା କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index a95244ae68e8..6cc4f1998183 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"ਸਮਰਾਟ"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"ਚੁਪੱਤਰੀ"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"ਅਗਿਆਤ ਪੋਰਟਰੇਟ"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"ਅਗਿਆਤ ਲੈਂਡਸਕੇਪ"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ਰੱਦ ਕੀਤਾ ਗਿਆ"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ਠੀਕ ਹੈ"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"ਬੈਟਰੀ ਸੇਵਰ ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ ਅਤੇ ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ ਅਤੇ ਕੁਝ ਖਾਸ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸੀਮਤ ਜਾਂ ਬੰਦ ਕਰਦਾ ਹੈ।\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"ਬੈਟਰੀ ਸੇਵਰ ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ ਅਤੇ ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ ਅਤੇ ਕੁਝ ਖਾਸ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸੀਮਤ ਜਾਂ ਬੰਦ ਕਰਦਾ ਹੈ।"</string> <string name="data_saver_description" msgid="4995164271550590517">"ਡਾਟਾ ਵਰਤੋਂ ਘਟਾਉਣ ਵਿੱਚ ਮਦਦ ਲਈ, ਡਾਟਾ ਸੇਵਰ ਕੁਝ ਐਪਾਂ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਟਾ ਭੇਜਣ ਜਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤਮਾਨ ਤੌਰ \'ਤੇ ਵਰਤੀ ਜਾ ਰਹੀ ਐਪ ਡਾਟਾ \'ਤੇ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਉਹ ਇੰਝ ਕਦੇ-ਕਦਾਈਂ ਕਰ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸ ਦਾ ਮਤਲਬ ਇਹ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਚਿੱਤਰ ਤਦ ਤੱਕ ਨਹੀਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕੀਤੇ ਜਾਂਦੇ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ \'ਤੇ ਟੈਪ ਨਹੀਂ ਕਰਦੇ।"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ਕੀ ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"ਚਾਲੂ ਕਰੋ"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ਇਸ ਸੂਚਨਾ ਦਾ ਦਰਜਾ ਘਟਾ ਕੇ ਸ਼ਾਂਤ \'ਤੇ ਸੈੱਟ ਕੀਤਾ ਗਿਆ। ਵਿਚਾਰ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਲਈ ਟੈਪ ਕਰੋ।"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ਇਸ ਸੂਚਨਾ ਦਾ ਦਰਜਾ ਵਧਾ ਦਿੱਤਾ ਗਿਆ। ਵਿਚਾਰ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਲਈ ਟੈਪ ਕਰੋ।"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ਇਸ ਸੂਚਨਾ ਦਾ ਦਰਜਾ ਘਟਾ ਦਿੱਤਾ ਗਿਆ। ਵਿਚਾਰ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਲਈ ਟੈਪ ਕਰੋ।"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"ਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ ਅਜ਼ਮਾਓ"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"ਸੁਝਾਈਆਂ ਗਈਆਂ ਕਾਰਵਾਈਆਂ, ਜਵਾਬਾਂ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਦੇ ਰਹਿਣ ਲਈ, ਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ ਨੂੰ ਚਾਲੂ ਕਰੋ। Android ਅਡੈਪਟਿਵ ਸੂਚਨਾਵਾਂ ਹੁਣ ਸਮਰਥਿਤ ਨਹੀਂ ਹਨ।"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ਚਾਲੂ ਕਰੋ"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ਹੁਣੇ ਨਹੀਂ"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"ਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"ਸੁਝਾਈਆਂ ਗਈਆਂ ਕਾਰਵਾਈਆਂ ਅਤੇ ਜਵਾਬ ਹੁਣ ਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ ਵੱਲੋਂ ਮੁਹੱਈਆ ਕਰਵਾਏ ਜਾਂਦੇ ਹਨ। Android ਅਡੈਪਟਿਵ ਸੂਚਨਾਵਾਂ ਹੁਣ ਸਮਰਥਿਤ ਨਹੀਂ ਹਨ।"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ਠੀਕ ਹੈ"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ਬੰਦ ਕਰੋ"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ਹੋਰ ਜਾਣੋ"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"ਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ ਸਾਰੀ ਸੂਚਨਾ ਸਮੱਗਰੀ ਨੂੰ ਪੜ੍ਹ ਸਕਦੀਆਂ ਹਨ, ਜਿਸ ਵਿੱਚ ਸੰਪਰਕ ਨਾਮ ਅਤੇ ਸੁਨੇਹੇ ਵਰਗੀ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਵੀ ਸ਼ਾਮਲ ਹੈ। ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਸੂਚਨਾਵਾਂ ਨੂੰ ਖਾਰਜ ਵੀ ਕਰ ਸਕਦੀ ਹੈ ਜਾਂ ਸੂਚਨਾਵਾਂ ਵਿੱਚ ਬਟਨਾਂ \'ਤੇ ਕਾਰਵਾਈਆਂ ਵੀ ਕਰ ਸਕਦੀ ਹੈ, ਜਿਵੇਂ ਕਿ ਫ਼ੋਨ ਕਾਲਾਂ ਦਾ ਜਵਾਬ ਦੇਣਾ।\n\nਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਤਰਜੀਹੀ ਮੋਡ ਨੂੰ ਚਾਲੂ ਜਾਂ ਬੰਦ ਵੀ ਕਰ ਸਕਦੀ ਹੈ ਅਤੇ ਸੰਬੰਧਿਤ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲ ਸਕਦੀ ਹੈ।"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 ਵਿੱਚ ਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ ਨੂੰ Android ਅਡੈਪਟਿਵ ਸੂਚਨਾਵਾਂ ਨਾਲ ਬਦਲ ਦਿੱਤਾ ਗਿਆ। ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਸੁਝਾਈਆਂ ਗਈਆਂ ਕਾਰਵਾਈਆਂ ਅਤੇ ਜਵਾਬ ਦਿਖਾਉਂਦੀ ਹੈ ਅਤੇ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰਦੀ ਹੈ।\n\nਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ ਸੂਚਨਾ ਸਮੱਗਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀਆਂ ਹਨ, ਜਿਸ ਵਿੱਚ ਸੰਪਰਕ ਨਾਮ ਅਤੇ ਸੁਨੇਹਿਆਂ ਵਰਗੀ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੈ। ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਸੂਚਨਾਵਾਂ ਨੂੰ ਖਾਰਜ ਵੀ ਕਰ ਸਕਦੀ ਹੈ ਜਾਂ ਸੂਚਨਾਵਾਂ ਦਾ ਜਵਾਬ ਵੀ ਦੇ ਸਕਦੀ ਹੈ, ਜਿਵੇਂ ਕਿ ਫ਼ੋਨ ਕਾਲਾਂ ਦਾ ਜਵਾਬ ਦੇਣਾ ਅਤੇ \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਨੂੰ ਕੰਟਰੋਲ ਕਰਨਾ।"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ਨਿਯਮਬੱਧ ਮੋਡ ਦੀ ਜਾਣਕਾਰੀ ਵਾਲੀ ਸੂਚਨਾ"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ਬੈਟਰੀ ਚਾਰਜ ਕਰਨ ਦੇ ਮਿੱਥੇ ਸਮੇਂ ਤੋਂ ਪਹਿਲਾਂ ਸ਼ਾਇਦ ਬੈਟਰੀ ਖਤਮ ਹੋ ਜਾਵੇ"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ਐਪਲੀਕੇਸ਼ਨ ਦਾ ਬ੍ਰਾਂਡ ਵਾਲਾ ਚਿੱਤਰ"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"ਪਹੁੰਚ ਸੈਟਿੰਗਾਂ ਦੀ ਜਾਂਚ ਕਰੋ"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ਸੇਵਾ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਨੂੰ ਦੇਖ ਅਤੇ ਕੰਟਰੋਲ ਕਰ ਸਕਦੀ ਹੈ। ਸਮੀਖਿਆ ਲਈ ਟੈਪ ਕਰੋ।"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 8233accfa3d3..69d9b1c6b962 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1817,28 +1817,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1875,8 +1864,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Nieznany pionowy"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Nieznany poziomy"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Anulowane"</string> @@ -1922,10 +1910,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Zaktualizowany przez administratora"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Usunięty przez administratora"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne i wybrane funkcje.\n\n"<annotation id="url">"Więcej informacji"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne i wybrane funkcje."</string> <string name="data_saver_description" msgid="4995164271550590517">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Włączyć Oszczędzanie danych?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Włącz"</string> @@ -2165,12 +2151,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"To powiadomienie zostało zmienione na Ciche. Kliknij, by przesłać opinię."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Podniesiono ważność tego powiadomienia. Kliknij, by przesłać opinię."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Obniżono ważność tego powiadomienia. Kliknij, by przesłać opinię."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Wypróbuj ulepszone powiadomienia"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Aby nadal otrzymywać sugestie działań oraz odpowiedzi i inne podpowiedzi, włącz ulepszone powiadomienia. Powiadomienia adaptacyjne w Androidzie nie są już obsługiwane."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Włącz"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Nie teraz"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Ulepszone powiadomienia"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Sugerowane działania i odpowiedzi pojawiają się teraz w ulepszonych powiadomieniach. Powiadomienia adaptacyjne w Androidzie nie są już obsługiwane."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Wyłącz"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Więcej informacji"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Ulepszone powiadomienia mogą czytać wszystkie powiadomienia, w tym dane osobowe takie jak nazwy kontaktów i treść wiadomości. Funkcja będzie też mogła odrzucać powiadomienia oraz używać zawartych w nich przycisków, np. odbierać połączenia telefoniczne.\n\nMoże również włączać i wyłączać tryb Priorytet oraz zmieniać powiązane ustawienia."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"W Androidzie 12 ulepszone powiadomienia zastąpiły powiadomienia adaptacyjne. Ta funkcja pokazuje sugerowane działania i odpowiedzi oraz porządkuje powiadomienia.\n\nUlepszone powiadomienia mogą czytać wszystkie powiadomienia, w tym dane osobowe takie jak nazwy kontaktów i treść wiadomości. Funkcja może też zamykać powiadomienia oraz reagować na nie, np. odbierać połączenia telefoniczne i sterować trybem Nie przeszkadzać."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Powiadomienie z informacją o trybie rutynowym"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria może się wyczerpać przed zwykłą porą ładowania"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Włączono Oszczędzanie baterii, by wydłużyć czas pracy na baterii"</string> @@ -2369,4 +2355,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Wizerunek marki aplikacji"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Sprawdź ustawienia dostępu"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"Usługa <xliff:g id="SERVICE_NAME">%s</xliff:g> może wyświetlać i kontrolować ekran. Kliknij, aby sprawdzić."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index d0d05226de6a..412bf86d78aa 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Retrato desconhecido"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Paisagem desconhecido"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelado"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos específicos.\n\n"<annotation id="url">"Saiba mais"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos específicos."</string> <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Esta notificação foi rebaixada a Silenciosa. Toque para enviar seu feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificação foi classificada com maior prioridade. Toque para enviar seu feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificação foi classificada com menor prioridade. Toque para enviar seu feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Testar notif. aprimoradas"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para continuar a receber sugestões de ações, respostas e muito mais, ative as notificações aprimoradas. As Notificações adaptáveis do Android não estão mais disponíveis."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Ativar"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Agora não"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificações aprimoradas"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"As ações e respostas sugeridas agora são fornecidas pelas notificações aprimoradas. As Notificações adaptáveis do Android não estão mais disponíveis."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desativar"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saiba mais"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"As notificações aprimoradas podem ler todo o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Além disso, esse recurso pode dispensar notificações e usar os botões delas para, por exemplo, atender chamadas telefônicas.\n\nEle também pode ativar ou desativar o modo Prioridade e mudar as configurações relacionadas."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"No Android 12, as notificações aprimoradas substituíram as Notificações adaptáveis. Esse recurso exibe ações e respostas sugeridas, além de organizar suas notificações.\n\nAs notificações aprimoradas podem acessar o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Elas também podem dispensar ou responder às notificações, como atender chamadas telefônicas e controlar o Não perturbe."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informação do modo rotina"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"A bateria pode acabar antes da recarga normal"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"A Economia de bateria foi ativada para aumentar a duração da carga"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imagem da marca do aplicativo"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Confira as configurações de acesso"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"O serviço <xliff:g id="SERVICE_NAME">%s</xliff:g> pode ver e controlar sua tela. Toque para revisar."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index dd3d1b414d4f..ec7bba760c08 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Vertical desconhecido"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Horizontal desconhecido"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelada"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu gestor"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado pelo seu gestor"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"A Poupança de bateria ativa o tema escuro e limita ou desativa a atividade em segundo plano, alguns efeitos visuais e determinadas funcionalidades.\n\n"<annotation id="url">"Saiba mais"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"A Poupança de bateria ativa o tema escuro e limita ou desativa a atividade em segundo plano, alguns efeitos visuais e determinadas funcionalidades."</string> <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas aplicações enviem ou recebam dados em segundo plano. Uma determinada app que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Pretende ativar a Poupança de dados?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Esta notificação foi despromovida para Silenciosa. Toque para fornecer feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificação passou para uma classificação superior. Toque para fornecer feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificação passou para uma classificação inferior. Toque para fornecer feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Experimente as not. melhoradas"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para continuar a obter sugestões de ações, respostas e muito mais, ative as notificações melhoradas. As notificações adaptáveis do Android já não são suportadas."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Ativar"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Agora não"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificações melhoradas"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"As ações e as respostas sugeridas são agora fornecidas por notificações melhoradas. As notificações adaptáveis do Android já não são suportadas."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desativar"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saber mais"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"As notificações melhoradas podem ler todo o conteúdo das notificações, incluindo informações pessoais como nomes de contactos e mensagens. Esta funcionalidade também pode ignorar notificações ou acionar botões em notificações, como atender chamadas telefónicas.\n\nAlém disso, esta funcionalidades pode ativar ou desativar o modo Prioridade e alterar as definições relacionadas."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"As notificações melhoradas substituíram as notificações adaptáveis do Android no Android 12. Esta funcionalidade mostra ações e respostas sugeridas e organiza as suas notificações.\n\nAs notificações melhoradas podem aceder a todo o conteúdo das notificações, incluindo informações pessoais como nomes de contactos e mensagens. Esta funcionalidade também pode ignorar ou responder a notificações, como atender chamadas telefónicas e controlar o modo Não incomodar."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informações do Modo rotina"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Pode ficar sem bateria antes do carregamento habitual"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Poupança de bateria ativada para prolongar a duração da bateria"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imagem de branding da aplicação."</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Verifique as definições de acesso"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"O serviço <xliff:g id="SERVICE_NAME">%s</xliff:g> pode ver e controlar o seu ecrã. Toque para rever."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index d0d05226de6a..412bf86d78aa 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Retrato desconhecido"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Paisagem desconhecido"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Cancelado"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos específicos.\n\n"<annotation id="url">"Saiba mais"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"A Economia de bateria ativa o tema escuro e limita ou desativa as atividades em segundo plano, alguns efeitos visuais e recursos específicos."</string> <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Esta notificação foi rebaixada a Silenciosa. Toque para enviar seu feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Esta notificação foi classificada com maior prioridade. Toque para enviar seu feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Esta notificação foi classificada com menor prioridade. Toque para enviar seu feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Testar notif. aprimoradas"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para continuar a receber sugestões de ações, respostas e muito mais, ative as notificações aprimoradas. As Notificações adaptáveis do Android não estão mais disponíveis."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Ativar"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Agora não"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificações aprimoradas"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"As ações e respostas sugeridas agora são fornecidas pelas notificações aprimoradas. As Notificações adaptáveis do Android não estão mais disponíveis."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desativar"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saiba mais"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"As notificações aprimoradas podem ler todo o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Além disso, esse recurso pode dispensar notificações e usar os botões delas para, por exemplo, atender chamadas telefônicas.\n\nEle também pode ativar ou desativar o modo Prioridade e mudar as configurações relacionadas."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"No Android 12, as notificações aprimoradas substituíram as Notificações adaptáveis. Esse recurso exibe ações e respostas sugeridas, além de organizar suas notificações.\n\nAs notificações aprimoradas podem acessar o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Elas também podem dispensar ou responder às notificações, como atender chamadas telefônicas e controlar o Não perturbe."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informação do modo rotina"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"A bateria pode acabar antes da recarga normal"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"A Economia de bateria foi ativada para aumentar a duração da carga"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imagem da marca do aplicativo"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Confira as configurações de acesso"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"O serviço <xliff:g id="SERVICE_NAME">%s</xliff:g> pode ver e controlar sua tela. Toque para revisar."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index e5e960f95db8..1104832b596f 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1795,28 +1795,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super-B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1853,8 +1842,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Portret necunoscut"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Peisaj necunoscut"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Anulat"</string> @@ -1899,10 +1887,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizat de administratorul dvs."</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Șters de administratorul dvs."</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Economisirea bateriei activează tema întunecată și dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții.\n\n"<annotation id="url">"Aflați mai multe"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Economisirea bateriei activează tema întunecată și dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții."</string> <string name="data_saver_description" msgid="4995164271550590517">"Pentru a contribui la reducerea utilizării de date, Economizorul de date împiedică unele aplicații să trimită sau să primească date în fundal. O aplicație pe care o folosiți poate accesa datele, însă mai rar. Aceasta poate însemna, de exemplu, că imaginile se afișează numai după ce le atingeți."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Activați Economizorul de date?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activați"</string> @@ -2132,12 +2118,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Notificarea a fost mutată în jos la Silențioasă. Atingeți pentru a oferi feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Notificarea a fost mutată la un nivel superior. Atingeți pentru a oferi feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Notificarea a fost mutată la un nivel inferior. Atingeți pentru a oferi feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Încercați notificările optimizate"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ca să primiți în continuare acțiuni sugerate, răspunsuri și altele, activați notificările optimizate. Notificările adaptive Android nu mai sunt acceptate."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Activați"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Nu acum"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Notificări optimizate"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Acțiunile și răspunsurile sugerate sunt acum trimise prin notificări optimizate. Notificările adaptive Android nu mai sunt acceptate."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Dezactivați"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Aflați mai multe"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Notificările optimizate pot citi tot conținutul notificărilor, inclusiv informații cu caracter personal, precum mesajele și numele persoanelor de contact. În plus, funcția poate să închidă notificări sau să acționeze asupra butoanelor din notificări, inclusiv să răspundă la apeluri telefonice.\n\nÎn plus, funcția poate să activeze sau să dezactiveze modul Cu prioritate și să schimbe setările asociate."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Notificările optimizate au înlocuit Notificările adaptive Android de pe Android 12. Această funcție afișează acțiuni și răspunsuri sugerate și vă organizează notificările.\n\nNotificările optimizate pot accesa conținutul notificărilor, inclusiv informații cu caracter personal, precum mesajele și numele persoanelor de contact. În plus, funcția poate să închidă sau să răspundă la notificări, de exemplu, să răspundă la apeluri telefonice și să gestioneze opțiunea Nu deranja."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificare pentru informații despre modul Rutină"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria se poate descărca înainte de încărcarea obișnuită"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Economisirea bateriei este activată pentru a prelungi durata de funcționare a bateriei"</string> @@ -2335,4 +2321,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imaginea de branding a aplicației"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Verificați setările pentru acces"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> poate să vadă și să vă controleze ecranul. Atingeți pentru a examina."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 55d6ac8f65de..b4910175cc6f 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1554,7 +1554,7 @@ </plurals> <string name="action_mode_done" msgid="2536182504764803222">"Готово"</string> <string name="progress_erasing" msgid="6891435992721028004">"Очистка единого хранилища…"</string> - <string name="share" msgid="4157615043345227321">"Отправить"</string> + <string name="share" msgid="4157615043345227321">"Поделиться"</string> <string name="find" msgid="5015737188624767706">"Найти"</string> <string name="websearch" msgid="5624340204512793290">"Веб-поиск"</string> <string name="find_next" msgid="5341217051549648153">"Cлед."</string> @@ -1817,28 +1817,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1875,8 +1864,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kaku"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Неизвестный вертикальный формат"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Неизвестный горизонтальный формат"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Печать отменена"</string> @@ -1922,10 +1910,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Обновлено администратором"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Удалено администратором"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, некоторые визуальные эффекты и определенные функции.\n\n"<annotation id="url">"Подробнее…"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, некоторые визуальные эффекты и определенные функции."</string> <string name="data_saver_description" msgid="4995164271550590517">"В режиме экономии трафика фоновая передача данных для некоторых приложений отключена. Приложение, которым вы пользуетесь, может получать и отправлять данные, но реже, чем обычно. Например, изображения могут не загружаться, пока вы не нажмете на них."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Включить экономию трафика?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Включить"</string> @@ -2146,7 +2132,7 @@ <string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ОТКРЫТЬ"</string> <string name="harmful_app_warning_title" msgid="8794823880881113856">"Обнаружено вредоносное приложение"</string> <string name="slices_permission_request" msgid="3677129866636153406">"Приложение \"<xliff:g id="APP_0">%1$s</xliff:g>\" запрашивает разрешение на показ фрагментов приложения \"<xliff:g id="APP_2">%2$s</xliff:g>\"."</string> - <string name="screenshot_edit" msgid="7408934887203689207">"Редактировать"</string> + <string name="screenshot_edit" msgid="7408934887203689207">"Изменить"</string> <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Для звонков и уведомлений включен вибросигнал."</string> <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Для звонков и уведомлений отключен звук."</string> <string name="notification_channel_system_changes" msgid="2462010596920209678">"Системные изменения"</string> @@ -2165,12 +2151,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Уровень важности этого уведомления был понижен до \"Без звука\". Нажмите, чтобы отправить отзыв."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Уровень важности этого уведомления был повышен. Нажмите, чтобы отправить отзыв."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Уровень важности этого уведомления был понижен. Нажмите, чтобы отправить отзыв."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Улучшенные уведомления"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Чтобы по-прежнему пользоваться рекомендуемыми действиями, ответами и другими подсказками, включите улучшенные уведомления. Адаптивные уведомления для Android больше не поддерживаются."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Включить"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не сейчас"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Улучшенные уведомления"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Быстрые ответы и действия теперь включены в улучшенные уведомления. Адаптивные уведомления для Android больше не поддерживаются."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ОК"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Отключить"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Подробнее"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Улучшенным уведомлениям доступно содержимое всех уведомлений, в том числе личная информация, такая как имена контактов и сообщения. У этой функции также есть право закрывать уведомления и нажимать кнопки в них, например отвечать на звонки.\n\nКроме того, улучшенные уведомления могут включать и отключать режим \"Только важные\" и изменять связанные с ним настройки."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"В Android 12 адаптивные уведомления заменены улучшенными. Эта функция упорядочивает все ваши уведомления и подсказывает ответы и действия.\n\nЕй доступно содержимое всех уведомлений, в том числе личная информация, такая как имена контактов и сообщения. Также эта функция может закрывать уведомления и нажимать кнопки в них, например отвечать на звонки или управлять режимом \"Не беспокоить\"."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Уведомление о батарее"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарея может разрядиться"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Чтобы увеличить время работы от батареи, был включен режим энергосбережения."</string> @@ -2369,4 +2355,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Образ бренда приложения"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Проверьте настройки доступа"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> просматривать и контролировать то, что отображается на вашем экране. Нажмите здесь, чтобы узнать больше."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 0130d1ef484a..7e5066c46875 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"නොදන්නා සිරස් දිශානතිය"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"නොදන්නා තිරස් දිශානතිය"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"අවලංගු කරන ලදි"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"ඔබගේ පරිපාලක මඟින් යාවත්කාලීන කර ඇත"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ඔබගේ පරිපාලක මඟින් මකා දමා ඇත"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"හරි"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"බැටරි සුරැකුම අඳුරු තේමාව ක්රියාත්මක කර පසුබිම් ක්රියාකාරකම්, සමහර දෘශ්ය ප්රයෝග සහ යම් විශේෂාංග ක්රියාවිරහිත හෝ සීමා කරයි.\n\n"<annotation id="url">"තව දැන ගන්න"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"බැටරි සුරැකුම අඳුරු තේමාව ක්රියාත්මක කර පසුබිම් ක්රියාකාරකම්, සමහර දෘශ්ය ප්රයෝග සහ යම් විශේෂාංග ක්රියාවිරහිත හෝ සීමා කරයි."</string> <string name="data_saver_description" msgid="4995164271550590517">"දත්ත භාවිතය අඩු කිරීමට උදවු වීමට, දත්ත සුරැකුම සමහර යෙදුම් පසුබිමින් දත්ත යැවීම සහ ලබා ගැනීම වළක්වයි. ඔබ දැනට භාවිත කරන යෙදුමකට දත්ත වෙත පිවිසීමට හැකිය, නමුත් එසේ කරන්නේ කලාතුරකින් විය හැකිය. මෙයින් අදහස් වන්නේ, උදාහරණයක් ලෙස, එම රූප ඔබ ඒවාට තට්ටු කරන තෙක් සංදර්ශනය නොවන බවය."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"දත්ත සුරැකුම ක්රියාත්මක කරන්නද?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"ක්රියාත්මක කරන්න"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"මෙම දැනුම්දීම නිහඬ වෙත පහත දමන ලදී. ප්රතිපෝෂණය ලබා දීමට තට්ටු කරන්න."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"මෙම දැනුම්දීම ඉහළට ශ්රේණිගත කරන ලදී. ප්රතිපෝෂණය ලබා දීමට තට්ටු කරන්න."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"මෙම දැනුම්දීම පහළට ශ්රේණිගත කරන ලදී. ප්රතිපෝෂණය ලබා දීමට තට්ටු කරන්න."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"දියුණු කළ දැනුම්දීම් උත්සාහ ක."</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"යෝජිත ක්රියා, පිළිතුරු සහ තවත් දේ ලබා ගැනීම සඳහා, වැඩි දියුණු කළ දැනුම්දීම් ක්රියාත්මක කරන්න. Android අනුවර්තී දැනුම්දීම් තවදුරටත් සහාය නොදක්වයි."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ක්රියාත්මක කරන්න"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"දැන් නොවේ"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"වැඩිදියුණු කළ දැනුම්දීම්"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"යෝජිත ක්රියා සහ පිළිතුරු දැන් වැඩි දියුණු කරන ලද දැනුම්දීම් මගින් සපයනු ලැබේ. Android අනුවර්තී දැනුම්දීම් තවදුරටත් සහාය නොදක්වයි."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"හරි"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ක්රියාවිරහිත කරන්න"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"තව දැන ගන්න"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"වැඩිදියුණු කළ දැනුම්දීම්වලට සම්බන්ධතා නම් සහ පණිවිඩ වැනි පුද්ගලික තොරතුරු ඇතුළුව, සියලු දැනුම්දීම් අන්තර්ගතය කියවිය හැකිය. මෙම විශේෂාංගයට දැනුම්දීම් ඉවත දැමීමට හෝ දුරකථන ඇමතුම්වලට පිළිතුරු දීම වැනි, දැනුම්දීම්වල බොත්තම් මත ක්රියා සිදු කිරීමටද හැකිය.\n\nමෙම විශේෂාංගයට ප්රමුඛතා ප්රකාරය ක්රියාත්මක හෝ ක්රියාවිරහිත කිරීමට සහ අදාළ සැකසීම් වෙනස් කිරීමටද හැකිය."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"වැඩිදියුණු කළ දැනුම්දීම් Android 12 හි Android අනුවර්තී දැනුම්දීම් ප්රතිස්ථාපනය කරයි. මෙම විශේෂාංගය යෝජිත ක්රියා සහ පිළිතුරු පෙන්වන අතර, ඔබගේ දැනුම්දීම් සංවිධානය කරයි.\n\nවැඩිදියුණු කළ දැනුම්දීම්වලට සම්බන්ධතා නම් සහ පණිවිඩ වැනි පුද්ගලික තොරතුරු ඇතුළුව, සියලු දැනුම්දීම් අන්තර්ගතය වෙත ප්රවේශ විය හැකිය. මෙම විශේෂාංගයට දැනුම්දීම් ඉවත දැමීමට හෝ දුරකථන ඇමතුම්වලට පිළිතුරු දීම සහ බාධා නොකරන්න පාලනය කිරීම වැනි, දැනුම්දීම්වලට ප්රතිචාර දැක්වීමටද හැකිය."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"දිනචරියා ප්රකාර තතු දැනුම්දීම"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"බැටරිය සුපුරුදු ආරෝපණයට පෙර ඉවර විය හැක"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"බැටරි සුරැකුම බැටරි ආයු කාලය දීර්ඝ කිරීමට සක්රිය කෙරිණි"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"යෙදුම් සන්නම් කිරීමේ රූපය"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"ප්රවේශ සැකසීම් පරීක්ෂා කරන්න"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> හට ඔබගේ තිරය බැලීමට සහ පාලනය කිරීමට හැකිය. සමාලෝචනය කිරීමට තට්ටු කරන්න."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index e2da90da685d..6f151306f1fc 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -325,7 +325,7 @@ <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"prístup k vašej fyzickej aktivite"</string> <string name="permgrouplab_camera" msgid="9090413408963547706">"Fotoaparát"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"fotenie a natáčanie videí"</string> - <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"Zariadenia v okolí"</string> + <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"Zariadenia nablízku"</string> <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"objavovať a pripájať zariadenia v okolí"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"Zoznam hovorov"</string> <string name="permgroupdesc_calllog" msgid="2026996642917801803">"čítať a zapisovať do zoznamu hovorov"</string> @@ -1753,7 +1753,7 @@ <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="3222994553174604132">"Mimoriadne stmavenie"</string> + <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Veľmi tmavé"</string> <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> @@ -1817,28 +1817,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1875,8 +1864,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Neznáma veľkosť papiera na výšku"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Neznáma veľkosť papiera na šírku"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Zrušené"</string> @@ -1922,10 +1910,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizoval správca"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Odstránil správca"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty a určité funkcie.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty a určité funkcie."</string> <string name="data_saver_description" msgid="4995164271550590517">"S cieľom znížiť spotrebu dát bráni šetrič dát niektorým aplikáciám odosielať alebo prijímať dáta na pozadí. Aplikácia, ktorú práve používate, môže využívať dáta, ale možno to bude robiť menej často. Môže to napríklad znamenať, že sa obrázky zobrazia, až keď na ne klepnete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnúť šetrič dát?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnúť"</string> @@ -2165,12 +2151,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Toto upozornenie bolo znížené na Tiché. Klepnutím nám poskytnite spätnú väzbu."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Toto upozornenie bolo preradené vyššie. Klepnutím nám poskytnite spätnú väzbu."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Toto upozornenie bolo preradené nižšie. Klepnutím nám poskytnite spätnú väzbu."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Skúste zlepšené upozornenia"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ak chcete ďalej dostávať navrhované akcie, odpovede a ďalší obsah, zapnite zlepšené upozornenia. Adaptívne upozornenia Androidu už nie sú podporované."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Zapnúť"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Teraz nie"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Zlepšené upozornenia"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Navrhované akcie a odpovede budú odteraz poskytované zlepšenými upozorneniami. Adaptívne upozornenia Androidu už nie sú podporované."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Vypnúť"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Ďalšie informácie"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Zlepšené upozornenia môžu čítať všetok obsah upozornení vrátane osobných údajov, ako sú mená kontaktov a správy. Táto funkcia tiež môže rušiť upozornenia alebo aktivovať tlačidlá v upozorneniach, napríklad na prijatie telefonických hovorov.\n\nTáto funkcia môže tiež zapnúť alebo vypnúť režim priority a zmeniť súvisiace nastavenia."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Adaptívne upozornenia Androidu boli v Androide 12 nahradené zlepšenými upozorneniami. Táto funkcia zobrazuje navrhované akcie aj odpovede a organizuje vaše upozornenia.\n\nZlepšené upozornenia majú prístup k obsahu upozornení vrátane osobných údajov, ako sú mená kontaktov a správy. Táto funkcia tiež môže zavrieť upozornenia alebo na ne reagovať, napríklad prijať telefonáty a ovládať režim bez vyrušení."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Upozornenie s informáciami o rutinnom režime"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batéria sa môže vybiť pred obvyklým nabitím"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Bol aktivovaný šetrič batérie na predĺženie výdrže batérie"</string> @@ -2369,4 +2355,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imidž značky aplikácie"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Kontrola nastavení prístupu"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> môže zobraziť a ovládať vašu obrazovku. Skontrolujte to klepnutím."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 01eaed689f06..b128fab63f2a 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1864,8 +1864,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Neznano pokončno"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Neznano ležeče"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Preklicano"</string> @@ -1911,10 +1910,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Posodobil skrbnik"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisal skrbnik"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"V redu"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Varčevanje z energijo baterije vklopi temno temo ter omeji ali izklopi dejavnost v ozadju, nekatere vizualne učinke in določene funkcije.\n\n"<annotation id="url">"Več o tem"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Varčevanje z energijo baterije vklopi temno temo ter omeji ali izklopi dejavnost v ozadju, nekatere vizualne učinke in določene funkcije."</string> <string name="data_saver_description" msgid="4995164271550590517">"Zaradi zmanjševanja prenesene količine podatkov funkcija varčevanja s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Vklop varčevanja s podatki?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Vklopi"</string> @@ -2135,7 +2132,7 @@ <string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"VSEENO ODPRI"</string> <string name="harmful_app_warning_title" msgid="8794823880881113856">"Zaznana je bila škodljiva aplikacija"</string> <string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati izreze aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string> - <string name="screenshot_edit" msgid="7408934887203689207">"Urejanje"</string> + <string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string> <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibriranje bo vklopljeno za klice in obvestila"</string> <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Zvonjenje bo izklopljeno za klice in obvestila"</string> <string name="notification_channel_system_changes" msgid="2462010596920209678">"Sistemske spremembe"</string> @@ -2154,12 +2151,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"To obvestilo je bilo uvrščeno nižje – med obvestila brez zvoka. Dotaknite se, če želite poslati povratne informacije."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"To obvestilo je bilo uvrščeno višje. Dotaknite se, če želite poslati povratne informacije."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"To obvestilo je bilo uvrščeno nižje. Dotaknite se, če želite poslati povratne informacije."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Preizkusite pametna obvestila"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Če želite še naprej prejemati predlagana dejanja, odgovore in drugo, vklopite pametna obvestila. Prilagodljiva obvestila Android niso več podprta."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Vklopi"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Ne zdaj"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Pametna obvestila"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Predlagana dejanja in odgovore zdaj zagotavljajo pametna obvestila. Prilagodljiva obvestila Android niso več podprta."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"V redu"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Izklopi"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Več o tem"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Pametna obvestila lahko preberejo vso vsebino obvestil, vključno z osebnimi podatki, kot so imena in sporočila stikov. Ta funkcija lahko tudi opusti obvestila in izvaja dejanja z gumbi v obvestilih, kot je sprejemanje telefonskih klicev.\n\nPoleg tega lahko ta funkcija vklopi ali izklopi prednostni način ter spremeni povezane nastavitve."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Pametna obvestila so v Androidu 12 zamenjala prilagodljiva obvestila Android. Ta funkcija prikazuje predlagana dejanja in odgovore ter organizira vaša obvestila.\n\nPametna obvestila lahko preberejo vso vsebino obvestil, vključno z osebnimi podatki, kot so imena in sporočila stikov. Ta funkcija lahko tudi opusti obvestila ali se odziva nanja (npr. sprejema telefonske klice in upravlja način »Ne moti«)."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutinsko informativno obvestilo o načinu delovanja"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterija se bo morda izpraznila, preden jo običajno priključite na polnjenje"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Vklopilo se je varčevanje z energijo baterije za podaljšanje časa delovanja baterije"</string> @@ -2358,4 +2355,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Podoba blagovne znamke aplikacije"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Preverite nastavitve dostopa"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"Storitev <xliff:g id="SERVICE_NAME">%s</xliff:g> si lahko ogleda in upravlja vaš zaslon. Dotaknite se za pregled."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 387bb4e11aea..c12383c0f941 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"\"Monarch\""</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"\"Quatro\""</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Vertikalisht i panjohur"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Orientim i panjohur horizontal"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Anuluar"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Përditësuar nga administratori"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Fshirë nga administratori"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Në rregull"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"\"Kursyesi i baterisë\" aktivizon \"Temën e errët\" dhe kufizon ose çaktivizon aktivitetin në sfond, disa efekte vizuale dhe veçori të caktuara.\n\n"<annotation id="url">"Mëso më shumë"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"\"Kursyesi i baterisë\" aktivizon \"Temën e errët\" dhe kufizon ose çaktivizon aktivitetin në sfond, disa efekte vizuale dhe veçori të caktuara."</string> <string name="data_saver_description" msgid="4995164271550590517">"Për të ndihmuar në reduktimin e përdorimit të të dhënave, \"Kursyesi i të dhënave\" pengon që disa aplikacione të dërgojnë apo të marrin të dhëna në sfond. Një aplikacion që po përdor aktualisht mund të ketë qasje te të dhënat, por këtë mund ta bëjë më rrallë. Kjo mund të nënkuptojë, për shembull, se imazhet nuk shfaqen kur troket mbi to."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Të aktivizohet \"Kursyesi i të dhënave\"?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivizo"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Ky njoftim është ulur në nivel si në heshtje. Trokit për të dhënë komente."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Ky njoftim është renditur më lart. Trokit për të dhënë komente."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Ky njoftim është renditur më poshtë. Trokit për të dhënë komente."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Provo njoftimet e përmirësuara"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Për të vazhduar të marrësh sugjerime për veprimet, përgjigjet etj., aktivizo njoftimet e përmirësuara. \"Njoftimet me përshtatje të Android\" nuk mbështeten më."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktivizo"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Jo tani"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Njoftimet e përmirësuara"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Veprimet dhe përgjigjet e sugjeruara tani ofrohen nga njoftimet e përmirësuara. \"Njoftimet me përshtatje të Android\" nuk mbështeten më."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Në rregull"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Çaktivizo"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Mëso më shumë"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Njoftimet e përmirësuara mund të lexojnë të gjithë përmbajtjen e njoftimeve, duke përfshirë edhe informacionet personale si emrat e kontakteve dhe mesazhet. Kjo veçori mund të heqë po ashtu njoftimet ose të veprojë mbi butonat te njoftimet, si p.sh. t\'u përgjigjet telefonatave.\n\nKjo veçori mund të aktivizojë ose të çaktivizojë po ashtu modalitetin \"Me përparësi\" dhe të ndryshojë cilësimet përkatëse."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Njoftimet e përmirësuara kanë zëvendësuar \"Njoftimet me përshtatje të Android\" në Android 12. Kjo veçori shfaq veprimet dhe përgjigjet e sugjeruara dhe organizon njoftimet e tua.\n\nNjoftimet e përmirësuara mund të kenë qasje te përmbajtja e njoftimeve, duke përfshirë informacionet personale si emrat e kontakteve dhe mesazhet. Kjo veçori mund t\'i heqë ose të përgjigjet po ashtu për njoftimet, si p.sh. t\'u përgjigjet telefonatave ose të kontrollojë modalitetin \"Mos shqetëso\"."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Njoftimi i informacionit të \"Modalitetit rutinë\""</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria mund të mbarojë përpara ngarkimit të zakonshëm"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"\"Kursyesi i baterisë\" u aktivizua për të rritur kohëzgjatjen e baterisë"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imazhi i vendosjes së aplikacionit të markës"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Kontrollo cilësimet e qasjes"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> mund ta shikojë dhe kontrollojë ekranin tënd. Trokit për ta rishikuar."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 00fe38da88ff..576487824baf 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1842,8 +1842,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Непозната величина, усправно"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Непозната величина, водоравно"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Отказано је"</string> @@ -1888,10 +1887,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирао је администратор"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Избрисао је администратор"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Потврди"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Уштеда батерије укључује Тамну тему и ограничава или искључује активности у позадини, неке визуелне ефекте и одређене функције.\n\n"<annotation id="url">"Сазнајте више"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Уштеда батерије укључује Тамну тему и ограничава или искључује активности у позадини, неке визуелне ефекте и одређене функције."</string> <string name="data_saver_description" msgid="4995164271550590517">"Да би се смањила потрошња података, Уштеда података спречава неке апликације да шаљу или примају податке у позадини. Апликација коју тренутно користите може да приступа подацима, али ће то чинити ређе. На пример, слике се неће приказивати док их не додирнете."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Желите да укључите Уштеду података?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Укључи"</string> @@ -2121,12 +2118,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Ово обавештење је деградирано у Нечујно. Додирните да бисте навели повратне информације."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Ово обавештење је рангирано више. Додирните да бисте навели повратне информације."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Ово обавештење је рангирано ниже. Додирните да бисте навели повратне информације."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Пробајте побољшана обавештења"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Укључите побољшана обавештења да бисте и даље добијали препоручене радње, одговоре и друго. Прилагодљива обавештења за Android више нису подржана."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Укључи"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не сада"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Побољшана обавештења"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Предложене радње и одговоре сада добијате помоћу побољшаних обавештења. Прилагодљива обавештења за Android више нису подржана."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Потврди"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Искључи"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Сазнајте више"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Побољшана обавештења могу да читају садржај свих обавештења, укључујући личне податке, попут имена контаката и порука. Ова функција може и да одбацује обавештења или активира дугмад у обавештењима, попут јављања на телефонске позиве.\n\nОва функција може и да укључи или искључи Приоритетни режим и да мења повезана подешавања."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Побољшана обавештења су заменила Android прилагодљива обавештења у Android-у 12. Ова функција показује предложене радње и одговоре и организује обавештења.\n\nПобољшана обавештења могу да приступају садржају обавештења, укључујући личне информације попут имена контаката и порука. Ова функција може и да одбацује обавештења или да одговара на њих, на пример, да се јавља на телефонске позиве и контролише режим Не узнемиравај."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Обавештење о информацијама Рутинског режима"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батерија ће се можда испразнити пре уобичајеног пуњења"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Уштеда батерије је активирана да би се продужило трајање батерије"</string> @@ -2324,4 +2321,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Имиџ бренда апликације"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Проверите подешавања приступа"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> може да прегледа и контролише екран. Додирните да бисте прегледали."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index a3c350bc71cb..ad511fb1f179 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -93,7 +93,7 @@ <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"Status för mobildata"</string> <string name="notification_channel_sms" msgid="1243384981025535724">"Sms"</string> <string name="notification_channel_voice_mail" msgid="8457433203106654172">"Röstmeddelanden"</string> - <string name="notification_channel_wfc" msgid="9048240466765169038">"Wi-Fi-samtal"</string> + <string name="notification_channel_wfc" msgid="9048240466765169038">"wifi-samtal"</string> <string name="notification_channel_sim" msgid="5098802350325677490">"Status för SIM-kort"</string> <string name="notification_channel_sim_high_prio" msgid="642361929452850928">"SIM-aviseringar med hög prioritet"</string> <string name="peerTtyModeFull" msgid="337553730440832160">"Peer-enheten begärde texttelefonläget FULL"</string> @@ -122,30 +122,30 @@ <string name="roamingText11" msgid="5245687407203281407">"Roamingbanner på"</string> <string name="roamingText12" msgid="673537506362152640">"Roamingbanner av"</string> <string name="roamingTextSearching" msgid="5323235489657753486">"Söker efter tjänst"</string> - <string name="wfcRegErrorTitle" msgid="3193072971584858020">"Det gick inte att konfigurera Wi-Fi-samtal"</string> + <string name="wfcRegErrorTitle" msgid="3193072971584858020">"Det gick inte att konfigurera wifi-samtal"</string> <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="468830943567116703">"Om du vill ringa samtal och skicka meddelanden via Wi-Fi ber du först operatören att konfigurera tjänsten. Därefter kan du aktivera Wi-Fi-samtal på nytt från Inställningar. (Felkod: <xliff:g id="CODE">%1$s</xliff:g>)"</item> + <item msgid="468830943567116703">"Om du vill ringa samtal och skicka meddelanden via wifi ber du först operatören att konfigurera tjänsten. Därefter kan du aktivera wifi-samtal på nytt från Inställningar. (Felkod: <xliff:g id="CODE">%1$s</xliff:g>)"</item> </string-array> <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="4795145070505729156">"Följande fel uppstod när Wi-Fi-samtal skulle registreras hos operatören: <xliff:g id="CODE">%1$s</xliff:g>"</item> + <item msgid="4795145070505729156">"Följande fel uppstod när wifi-samtal skulle registreras hos operatören: <xliff:g id="CODE">%1$s</xliff:g>"</item> </string-array> <!-- no translation found for wfcSpnFormat_spn (2982505428519096311) --> <skip /> - <string name="wfcSpnFormat_spn_wifi_calling" msgid="3165949348000906194">"Wi-Fi-samtal via <xliff:g id="SPN">%s</xliff:g>"</string> - <string name="wfcSpnFormat_spn_wifi_calling_vo_hyphen" msgid="3836827895369365298">"Wi-Fi-samtal med <xliff:g id="SPN">%s</xliff:g>"</string> + <string name="wfcSpnFormat_spn_wifi_calling" msgid="3165949348000906194">"wifi-samtal via <xliff:g id="SPN">%s</xliff:g>"</string> + <string name="wfcSpnFormat_spn_wifi_calling_vo_hyphen" msgid="3836827895369365298">"wifi-samtal med <xliff:g id="SPN">%s</xliff:g>"</string> <string name="wfcSpnFormat_wlan_call" msgid="4895315549916165700">"WLAN-samtal"</string> <string name="wfcSpnFormat_spn_wlan_call" msgid="255919245825481510">"WLAN-samtal via <xliff:g id="SPN">%s</xliff:g>"</string> - <string name="wfcSpnFormat_spn_wifi" msgid="7232899594327126970">"Wi-Fi via <xliff:g id="SPN">%s</xliff:g>"</string> - <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="8383917598312067365">"Wi-Fi-samtal | <xliff:g id="SPN">%s</xliff:g>"</string> + <string name="wfcSpnFormat_spn_wifi" msgid="7232899594327126970">"wifi via <xliff:g id="SPN">%s</xliff:g>"</string> + <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="8383917598312067365">"wifi-samtal | <xliff:g id="SPN">%s</xliff:g>"</string> <string name="wfcSpnFormat_spn_vowifi" msgid="6865214948822061486">"VoWifi via <xliff:g id="SPN">%s</xliff:g>"</string> - <string name="wfcSpnFormat_wifi_calling" msgid="6178935388378661755">"Wi-Fi-samtal"</string> - <string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string> - <string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi-samtal"</string> + <string name="wfcSpnFormat_wifi_calling" msgid="6178935388378661755">"wifi-samtal"</string> + <string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wifi"</string> + <string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"wifi-samtal"</string> <string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string> <string name="wifi_calling_off_summary" msgid="5626710010766902560">"Av"</string> - <string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Ring via Wi-Fi"</string> + <string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Ring via wifi"</string> <string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Ring via mobilnätverk"</string> - <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Endast Wi-Fi"</string> + <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Endast wifi"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> används som reserv för samtal"</string> @@ -512,14 +512,14 @@ <string name="permdesc_changeNetworkState" msgid="649341947816898736">"Tillåter att appen ändrar statusen för en nätverksanslutning."</string> <string name="permlab_changeTetherState" msgid="9079611809931863861">"ändra sammanlänkad anslutning"</string> <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Tillåter att appen ändrar statusen för en delad nätverksanslutning."</string> - <string name="permlab_accessWifiState" msgid="5552488500317911052">"visa Wi-Fi-anslutningar"</string> - <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Tillåter att appen kommer åt information om Wi-Fi-nätverk, till exempel om Wi-Fi är aktiverat och namn på anslutna Wi-Fi-enheter."</string> - <string name="permlab_changeWifiState" msgid="7947824109713181554">"anslut och koppla från Wi-Fi"</string> - <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Tillåter att appen ansluter till och kopplar från Wi-Fi-åtkomstpunkter samt gör ändringar i enhetens konfiguration för Wi-Fi-nätverk."</string> - <string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"tillåt Wi-Fi multicast-mottagning"</string> - <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"Tillåter att appen tar emot paket som skickats med multicast-adress till alla enheter i ett Wi-Fi-nätverk och inte bara till den här surfplattan. Detta drar mer batteri än när multicastläget inte används."</string> - <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"Tillåter att appen tar emot paket som skickats med multicast-adress till alla enheter i ett Wi-Fi-nätverk och inte bara till den här Android TV-enheten. Detta drar mer batteri än när multicastläget inte används."</string> - <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Tillåter att appen tar emot paket som skickats med multicast-adress till alla enheter i ett Wi-Fi-nätverk och inte bara till den här mobilen. Detta drar mer batteri än när multicastläget inte används."</string> + <string name="permlab_accessWifiState" msgid="5552488500317911052">"visa wifi-anslutningar"</string> + <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Tillåter att appen kommer åt information om wifi-nätverk, till exempel om wifi är aktiverat och namn på anslutna wifi-enheter."</string> + <string name="permlab_changeWifiState" msgid="7947824109713181554">"anslut och koppla från wifi"</string> + <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Tillåter att appen ansluter till och kopplar från wifi-åtkomstpunkter samt gör ändringar i enhetens konfiguration för wifi-nätverk."</string> + <string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"tillåt wifi multicast-mottagning"</string> + <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"Tillåter att appen tar emot paket som skickats med multicast-adress till alla enheter i ett wifi-nätverk och inte bara till den här surfplattan. Detta drar mer batteri än när multicastläget inte används."</string> + <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"Tillåter att appen tar emot paket som skickats med multicast-adress till alla enheter i ett wifi-nätverk och inte bara till den här Android TV-enheten. Detta drar mer batteri än när multicastläget inte används."</string> + <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Tillåter att appen tar emot paket som skickats med multicast-adress till alla enheter i ett wifi-nätverk och inte bara till den här mobilen. Detta drar mer batteri än när multicastläget inte används."</string> <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"få åtkomst till Bluetooth-inställningar"</string> <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Tillåter att appen konfigurerar den lokala Bluetooth-surfplattan samt upptäcker och parkopplar den med fjärranslutna enheter."</string> <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Tillåter att appen konfigurerar Bluetooth på Android TV-enheten samt upptäcker fjärrenheter och parkopplar enheten med dem."</string> @@ -1295,7 +1295,7 @@ <string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"Ljud för alarm"</string> <string name="ringtone_picker_title_notification" msgid="6387191794719608122">"Aviseringsljud"</string> <string name="ringtone_unknown" msgid="5059495249862816475">"Okänt"</string> - <string name="wifi_available_sign_in" msgid="381054692557675237">"Logga in på ett Wi-Fi-nätverk"</string> + <string name="wifi_available_sign_in" msgid="381054692557675237">"Logga in på ett wifi-nätverk"</string> <string name="network_available_sign_in" msgid="1520342291829283114">"Logga in på nätverket"</string> <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) --> <skip /> @@ -1311,7 +1311,7 @@ <string name="network_switch_metered_toast" msgid="501662047275723743">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string> <string-array name="network_switch_type_name"> <item msgid="2255670471736226365">"mobildata"</item> - <item msgid="5520925862115353992">"Wi-Fi"</item> + <item msgid="5520925862115353992">"Wifi"</item> <item msgid="1055487873974272842">"Bluetooth"</item> <item msgid="1616528372438698248">"Ethernet"</item> <item msgid="9177085807664964627">"VPN"</item> @@ -1576,10 +1576,10 @@ <string name="data_usage_warning_title" msgid="9034893717078325845">"Datavarning"</string> <string name="data_usage_warning_body" msgid="1669325367188029454">"Du har använt <xliff:g id="APP">%s</xliff:g> data"</string> <string name="data_usage_mobile_limit_title" msgid="3911447354393775241">"Gränsen för mobildata har nåtts"</string> - <string name="data_usage_wifi_limit_title" msgid="2069698056520812232">"Datagränsen för Wi-Fi har uppnåtts"</string> + <string name="data_usage_wifi_limit_title" msgid="2069698056520812232">"Datagränsen för wifi har uppnåtts"</string> <string name="data_usage_limit_body" msgid="3567699582000085710">"Data är pausade under resten av cykeln"</string> <string name="data_usage_mobile_limit_snoozed_title" msgid="101888478915677895">"Över gränsen för mobildata"</string> - <string name="data_usage_wifi_limit_snoozed_title" msgid="1622359254521960508">"Över gränsen för Wi-Fi-data"</string> + <string name="data_usage_wifi_limit_snoozed_title" msgid="1622359254521960508">"Över gränsen för wifi-data"</string> <string name="data_usage_limit_snoozed_body" msgid="545146591766765678">"Du överskridit den inställda gränsen med <xliff:g id="SIZE">%s</xliff:g>"</string> <string name="data_usage_restricted_title" msgid="126711424380051268">"Bakgrundsdata är begränsade"</string> <string name="data_usage_restricted_body" msgid="5338694433686077733">"Ta bort begränsning."</string> @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Porträtt – okänd storlek"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Landskap – okänd storlek"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Inställd"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Administratören uppdaterade paketet"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratören raderade paketet"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Batterisparläget aktiverar mörkt tema och begränsar eller inaktiverar bakgrundsaktivitet, vissa visuella effekter och vissa funktioner.\n\n"<annotation id="url">"Läs mer"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Batterisparläget aktiverar mörkt tema och begränsar eller inaktiverar bakgrundsaktivitet, vissa visuella effekter och vissa funktioner."</string> <string name="data_saver_description" msgid="4995164271550590517">"Med Databesparing kan du minska dataanvändningen genom att hindra en del appar från att skicka eller ta emot data i bakgrunden. Appar som du använder kan komma åt data, men det sker kanske inte lika ofta. Detta innebär t.ex. att bilder inte visas förrän du trycker på dem."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Vill du aktivera Databesparing?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivera"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Den här aviseringen har ändrats till Tyst. Tryck för att lämna feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Den här aviseringen har fått högre rankning. Tryck för att lämna feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Den här aviseringen har fått lägre rankning. Tryck för att lämna feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Testa förbättrade aviseringar"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Aktivera förbättrade aviseringar om du vill fortsätta att få rekommenderade åtgärder, svar och annat. Anpassade aviseringar för Android stöds inte längre."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aktivera"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Inte nu"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Förbättrade aviseringar"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Förslag på åtgärder och svar tillhandahålls nu via förbättrade aviseringar. Anpassade aviseringar för Android stöds inte längre."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Inaktivera"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Läs mer"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Förbättrade aviseringar kan läsa allt innehåll i aviseringar, inklusive personliga uppgifter som namn på kontakter och meddelanden. Funktionen kan även stänga aviseringar eller använda åtgärdsknappar i aviseringar, till exempel för att svara på telefonsamtal.\n\nFunktionen kan även aktivera och inaktivera prioritetsläget och ändra tillhörande inställningar."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Förbättrade aviseringar har ersatt Anpassade aviseringar för Android i Android 12. Den här funktionen visar förslag på åtgärder och svar och organiserar dina aviseringar.\n\nFörbättrade aviseringar har åtkomst till allt innehåll i aviseringar, inklusive personliga uppgifter som namn på kontakter och meddelanden. Funktionen kan även ignorera aviseringar eller utföra åtgärder utifrån dem, till exempel svara på telefonsamtal och styra Stör ej."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Avisering om rutinläge"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batteriet kan ta slut innan du brukar ladda det"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterisparläget har aktiverats för att utöka batteritiden"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Appens varumärkesbild"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Kontrollera åtkomstinställningar"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> kan visa och styra din skärm. Tryck för att granska."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 7eb9ddaa912f..04e2ff332116 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Mkao wima usiojulikana"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Mandhari yasiyojulikana"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Imeghairiwa"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Imesasishwa na msimamizi wako"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Imefutwa na msimamizi wako"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Sawa"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Kiokoa Betri huwasha Mandhari meusi na kudhibiti au kuzima shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele fulani.\n\n"<annotation id="url">"Pata maelezo zaidi"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Kiokoa Betri huwasha Mandhari meusi na kudhibiti au kuzima shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele fulani."</string> <string name="data_saver_description" msgid="4995164271550590517">"Ili kusaidia kupunguza matumizi ya data, Kiokoa Data huzuia baadhi ya programu kupokea na kutuma data chinichini. Programu ambayo unatumia sasa inaweza kufikia data, lakini si kila wakati. Kwa mfano, haitaonyesha picha hadi utakapozifungua."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Ungependa Kuwasha Kiokoa Data?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Washa"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Arifa hii ilishushwa hadhi kuwa Kimya. Gusa ili utoe maoni."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Arifa hii imeorodheshwa katika nafasi ya juu. Gusa ili utoe maoni."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Arifa hii imeorodheshwa katika nafasi ya chini. Gusa ili utoe maoni."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Jaribu arifa zilizoboreshwa"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ili uendelee kupata vitendo, majibu na mambo mengine yanayopendekezwa, washa arifa zilizoboreshwa. Arifa Zinazojirekebisha za Android hazitumiki tena."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Washa"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Si sasa"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Arifa zilizoboreshwa"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Majibu na vitendo vinavyopendekezwa sasa vinatolewa na arifa zilizoboreshwa. Arifa Zinazojirekebisha za Android hazitumiki tena."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Sawa"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Zima"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Pata maelezo zaidi"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Kipengele cha Arifa zilizoboreshwa kinaweza kusoma maudhui yote ya arifa, zikiwemo taarifa binafsi kama vile majina ya anwani na ujumbe. Kipengele hiki kinaweza pia kuondoa arifa au kuchukua hatua kwenye vitufe katika arifa, kama vile kujibu simu.\n\nKipengele hiki pia kinaweza kuwasha au kuzima hali ya Kipaumbele na kubadilisha mipangilio inayohusiana."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Kipengele cha Arifa Zilizoboreshwa kilichukua nafasi ya Arifa Zinazojirekebisha za Android katika Android 12. Kipengele hiki kinaonyesha majibu na vitendo vinavyopendekezwa na kupanga arifa zako.\n\nKipengele cha Arifa zilizoboreshwa kinaweza kufikia maudhui ya arifa, ikiwa ni pamoja na taarifa binafsi kama vile majina ya anwani na ujumbe. Kipengele hiki kinaweza pia kuondoa au kujibu arifa, kama vile kujibu simu na kudhibiti kipengele cha Usinisumbue."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Arifa ya maelezo ya Hali ya Kawaida"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Huenda betri itakwisha chaji mapema"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Imewasha Kiokoa Betri ili kurefusha muda wa matumizi ya betri"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Picha ya kuweka chapa kwenye programu"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Angalia mipangilio ya kufikia"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> inaweza kuangalia na kudhibiti skrini yako. Gusa ili ukague."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index e68a865f9cd4..6e3e1894d197 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -1707,8 +1707,8 @@ <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"முடிந்தது"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ஷார்ட்கட்டை முடக்கு"</string> <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="color_inversion_feature_name" msgid="326050048927789012">"நிற நேரெதிர் மாற்றம்"</string> + <string name="color_correction_feature_name" msgid="3655077237805422597">"நிறத் திருத்தம்"</string> <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"மிகக் குறைவான வெளிச்சம்"</string> <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> @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"மோனார்க்"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"குவார்டோ"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"பூல்ஸ்கேப்"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"அறியப்படாத நிலைபதிப்பு"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"அறியப்படாத நிலைபரப்பு"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ரத்துசெய்யப்பட்டது"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"உங்கள் நிர்வாகி நீக்கியுள்ளார்"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"சரி"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"பேட்டரி சேமிப்பான் டார்க் தீமை ஆன் செய்யும். பின்னணிச் செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள் மற்றும் குறிப்பிட்ட அம்சங்களைக் கட்டுப்படுத்தும் அல்லது ஆஃப் செய்யும்.\n\n"<annotation id="url">"மேலும் அறிக"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"பேட்டரி சேமிப்பான் டார்க் தீமை ஆன் செய்யும். பின்னணிச் செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள் மற்றும் குறிப்பிட்ட அம்சங்களைக் கட்டுப்படுத்தும் அல்லது ஆஃப் செய்யும்."</string> <string name="data_saver_description" msgid="4995164271550590517">"டேட்டா உபயோகத்தைக் குறைப்பதற்கு உதவ, பின்புலத்தில் டேட்டாவை அனுப்புவது அல்லது பெறுவதிலிருந்து சில ஆப்ஸை டேட்டா சேமிப்பான் தடுக்கும். தற்போது பயன்படுத்தும் ஆப்ஸானது எப்போதாவது டேட்டாவை அணுகலாம். எடுத்துக்காட்டாக, படங்களை நீங்கள் தட்டும் வரை அவை காட்டப்படாது."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"டேட்டா சேமிப்பானை இயக்கவா?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"இயக்கு"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"இந்த அறிவிப்பின் முக்கியத்துவம் நிசப்த நிலைக்குக் குறைத்து அமைக்கப்பட்டது. கருத்து தெரிவிக்க தட்டவும்."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"இந்த அறிவிப்பின் முக்கியத்துவம் உயர்த்தப்பட்டது. கருத்து தெரிவிக்க தட்டவும்."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"இந்த அறிவிப்பின் முக்கியத்துவம் குறைக்கப்பட்டது. கருத்து தெரிவிக்க தட்டவும்."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"மேம்பட்ட அறிவிப்புகளை முயல்க"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"பரிந்துரைக்கப்பட்ட செயல்பாடுகள், பதில்கள் மற்றும் பலவற்றையும் தொடர்ந்து பெற மேம்பட்ட அறிவிப்புகளை ஆன் செய்யவும். Android சூழலுக்கேற்ற அறிவிப்புகள் இனி ஆதரிக்கப்படாது."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ஆன் செய்"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"இப்போது வேண்டாம்"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"மேம்பட்ட அறிவிப்புகள்"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"பரிந்துரைக்கப்படும் செயல்களையும் பதில்களையும் இப்போது \'மேம்பட்ட அறிவிப்புகள்\' வழங்குகிறது. Android சூழலுக்கேற்ற அறிவிப்புகள் இனி ஆதரிக்கப்படாது."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"சரி"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ஆஃப் செய்"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"மேலும் அறிக"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"மேம்பட்ட அறிவிப்புகளால் அனைத்து அறிவிப்புகளின் உள்ளடக்கத்தையும் (தொடர்புகளின் பெயர்கள், மெசேஜ்கள் போன்ற தனிப்பட்ட தகவல்கள் உட்பட) படிக்க முடியும். இந்த அம்சத்தால் அறிவிப்புகளை நிராகரிக்கவோ அறிவிப்புகளிலுள்ள பட்டன்களை இயக்கவோ (அழைப்புகளுக்குப் பதிலளிப்பது போன்றவை) முடியும்.\n\nஇந்த அம்சத்தால் முன்னுரிமைப் பயன்முறையை இயக்கவோ முடக்கவோ முடியும் மற்றும் தொடர்புடைய அமைப்புகளை மாற்றவும் முடியும்."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 பதிப்பில் Android அடாப்டிவ் அறிவிப்புகள் இப்போது \'மேம்பட்ட அறிவிப்புகளாக\' மாற்றப்பட்டுள்ளது. இந்த அம்சம், பரிந்துரைக்கப்படும் செயல்களையும் பதில்களையும் காட்டும். மேலும் உங்கள் அறிவிப்புகளை ஒருங்கிணைக்கும்.\n\nமேம்பட்ட அறிவிப்புகளால் அனைத்து அறிவிப்புகளின் உள்ளடக்கத்தையும் (தொடர்புகளின் பெயர்கள், மெசேஜ்கள் போன்ற தனிப்பட்ட தகவல்கள் உட்பட) அணுக முடியும். இந்த அம்சத்தால் அறிவிப்புகளை நிராகரிக்கவும் அவற்றுக்குப் பதிலளிக்கவும்கூட (அழைப்புகளுக்குப் பதிலளிப்பது, தொந்தரவு செய்ய வேண்டாம் அம்சத்தைக் கட்டுப்படுத்துவது போன்றவை) முடியும்."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"வழக்கமான பேட்டரி சேமிப்பானுக்கான விவர அறிவிப்பு"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"வழக்கமாகச் சார்ஜ் செய்வதற்கு முன்பே பேட்டரி தீர்ந்துபோகக்கூடும்"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"பேட்டரி நிலையை நீட்டிக்க பேட்டரி சேமிப்பான் இயக்கப்பட்டுள்ளது"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ஆப்ஸ் பிராண்டிங் இமேஜ்"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"அணுகல் அமைப்புகளைச் சரிபாருங்கள்"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> சேவையால் உங்கள் திரையைப் பார்க்கவும் கட்டுப்படுத்தவும் முடியும். பார்க்கத் தட்டவும்."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 210ed4f1d190..9f5c24d9e272 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"మోనార్క్"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"క్వార్టో"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"ఫుల్స్కేప్"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"కాహు"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"కాకు2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"యు4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"తెలియని పొర్ట్రెయిట్"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"తెలియని ల్యాండ్స్కేప్"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"రద్దు చేయబడింది"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"మీ నిర్వాహకులు నవీకరించారు"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"మీ నిర్వాహకులు తొలగించారు"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"సరే"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేసి, బ్యాక్గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్లు, నిర్దిష్ట ఫీచర్లను పరిమితం చేస్తుంది లేదా ఆఫ్ చేస్తుంది.\n\n"<annotation id="url">"మరింత తెలుసుకోండి"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేసి, బ్యాక్గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్లు, నిర్దిష్ట ఫీచర్లను పరిమితం చేస్తుంది లేదా ఆఫ్ చేస్తుంది."</string> <string name="data_saver_description" msgid="4995164271550590517">"డేటా వినియోగాన్ని తగ్గించడంలో డేటా సేవర్ సహాయకరంగా ఉంటుంది. బ్యాక్గ్రౌండ్లో కొన్ని యాప్లు డేటాను పంపకుండా లేదా స్వీకరించకుండా నిరోధిస్తుంది. మీరు ప్రస్తుతం ఉపయోగిస్తోన్న యాప్, డేటాను యాక్సెస్ చేయగలదు. కానీ తక్కువ సార్లు మాత్రమే అలా చేయవచ్చు. ఉదాహరణకు, మీరు నొక్కే వరకు ఫోటోలు ప్రదర్శించబడవు."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"డేటా సేవర్ను ఆన్ చేయాలా?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"ఆన్ చేయి"</string> @@ -2099,12 +2085,17 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ఈ నోటిఫికేషన్ స్థాయి నిశ్శబ్దంగా ఉండేలా తగ్గించబడింది. ఫీడ్బ్యాక్ను అందించడానికి ట్యాప్ చేయండి."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ఈ నోటిఫికేషన్కు ఎక్కువ ర్యాంక్ ఇవ్వబడింది. ఫీడ్బ్యాక్ను అందించడానికి ట్యాప్ చేయండి."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"ఈ నోటిఫికేషన్కు తక్కువ ర్యాంక్ ఇవ్వబడింది. ఫీడ్బ్యాక్ను అందించడానికి ట్యాప్ చేయండి."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"మెరుగైన నోటిఫికేషన్ల ట్రై"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"సూచించిన చర్యలు, రిప్లయిలు, అలాగే మరిన్ని పొందడం కొనసాగించడానికి మెరుగైన నోటిఫికేషన్లను ఆన్ చేయండి. Android అనుకూల నోటిఫికేషన్లు ఇకపై సపోర్ట్ చేయవు."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"ఆన్ చేయి"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ఇప్పుడు కాదు"</string> + <!-- no translation found for nas_upgrade_notification_title (8436359459300146555) --> + <skip /> + <!-- no translation found for nas_upgrade_notification_content (5157550369837103337) --> + <skip /> + <!-- no translation found for nas_upgrade_notification_enable_action (3046406808378726874) --> + <skip /> + <!-- no translation found for nas_upgrade_notification_disable_action (3794833210043497982) --> + <skip /> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"మరింత తెలుసుకోండి"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"కాంటాక్ట్ పేర్లు, మెసేజ్లు వంటి వ్యక్తిగత సమాచారంతో సహా మెరుగైన నోటిఫికేషన్లు అన్ని నోటిఫికేషన్ కంటెంట్ను చదవగలవు. ఈ ఫీచర్ నోటిఫికేషన్లను తీసివేయవచ్చు లేదా ఫోన్ కాల్లకు సమాధానం ఇవ్వడం వంటి నోటిఫికేషన్లలోని బటన్లపై చర్యలు తీసుకోవచ్చు.\n\nఈ ఫీచర్ ప్రాధాన్యత మోడ్ను కూడా ఆన్ లేదా ఆఫ్ చేయవచ్చు, ఇది సంబంధిత సెట్టింగ్లను మార్చగలదు."</string> + <!-- no translation found for nas_upgrade_notification_learn_more_content (2353549817159426430) --> + <skip /> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"రొటీన్ మోడ్ సమాచార నోటిఫికేషన్"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"మామూలుగా ఛార్జ్ చేసేలోపు బ్యాటరీ ఖాళీ కావచ్చు"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి బ్యాటరీ సేవర్ యాక్టివేట్ చేయబడింది"</string> @@ -2301,4 +2292,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"యాప్ బ్రాండింగ్ ఇమేజ్"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"యాక్సెస్ సెట్టింగ్లను చెక్ చేయండి"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> మీ స్క్రీన్ను చూడవచ్చు, కంట్రోల్ చేయవచ్చు. రివ్యూ చేయడానికి ట్యాప్ చేయండి."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 5b00f7341fa2..3f338e6d31fe 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"กระดาษฟุลสแก๊ป"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super-B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"แนวตั้งไม่ทราบขนาด"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"แนวนอนไม่ทราบขนาด"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"ยกเลิก"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"อัปเดตโดยผู้ดูแลระบบ"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ลบโดยผู้ดูแลระบบ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ตกลง"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"โหมดประหยัดแบตเตอรี่จะเปิดใช้ธีมมืดและจำกัดหรือปิดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์บางส่วน\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"โหมดประหยัดแบตเตอรี่จะเปิดใช้ธีมมืดและจำกัดหรือปิดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์บางส่วน"</string> <string name="data_saver_description" msgid="4995164271550590517">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลโดยการใช้อินเทอร์เน็ตอยู่เบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงอินเทอร์เน็ตได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"เปิด"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"การแจ้งเตือนนี้มีการลดระดับเป็นแบบปิดเสียง แตะเพื่อแสดงความคิดเห็น"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"การแจ้งเตือนนี้มีการเพิ่มระดับ แตะเพื่อแสดงความคิดเห็น"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"การแจ้งเตือนนี้มีการลดระดับ แตะเพื่อแสดงความคิดเห็น"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"ลองใช้การแจ้งเตือนที่เพิ่มประสิทธิภาพ"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"หากต้องการรับการดําเนินการ การตอบ และอื่นๆ ที่แนะนําต่อไป ให้เปิดการแจ้งเตือนที่เพิ่มประสิทธิภาพ ไม่รองรับการแจ้งเตือนแบบปรับอัตโนมัติใน Android อีกต่อไป"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"เปิด"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ไว้ทีหลัง"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"การแจ้งเตือนที่เพิ่มประสิทธิภาพ"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"การดำเนินการและการตอบกลับที่แนะนำจะแสดงผ่านการแจ้งเตือนที่เพิ่มประสิทธิภาพ ไม่รองรับการแจ้งเตือนแบบปรับอัตโนมัติใน Android อีกต่อไป"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ตกลง"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ปิด"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ดูข้อมูลเพิ่มเติม"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"การแจ้งเตือนที่เพิ่มประสิทธิภาพจะอ่านเนื้อหาการแจ้งเตือนทั้งหมดได้ รวมถึงข้อมูลส่วนบุคคล เช่น ชื่อผู้ติดต่อและข้อความ ฟีเจอร์นี้ยังปิดการแจ้งเตือนหรือดำเนินการกับปุ่มต่างๆ ในการแจ้งเตือนได้ด้วย เช่น การรับสายเรียกเข้า\n\nอีกทั้งสามารถเปิดหรือปิดโหมดลำดับความสำคัญสูงและเปลี่ยนแปลงการตั้งค่าที่เกี่ยวข้อง"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"การแจ้งเตือนที่เพิ่มประสิทธิภาพมาแทนที่การแจ้งเตือนแบบปรับอัตโนมัติของ Android ใน Android 12 ฟีเจอร์นี้จะแสดงการดำเนินการและการตอบกลับที่แนะนำ ตลอดจนจัดระเบียบการแจ้งเตือน\n\nการแจ้งเตือนที่เพิ่มประสิทธิภาพจะเข้าถึงเนื้อหาของการแจ้งเตือนได้ ซึ่งรวมถึงข้อมูลส่วนบุคคล เช่น ชื่อผู้ติดต่อและข้อความ ฟีเจอร์นี้ยังปิดหรือตอบสนองต่อการแจ้งเตือนได้ด้วย เช่น การรับสายโทรศัพท์และการควบคุมโหมดห้ามรบกวน"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"การแจ้งเตือนข้อมูลโหมดกิจวัตร"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"แบตเตอรี่อาจหมดก่อนการชาร์จปกติ"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"เปิดใช้งานโหมดประหยัดแบตเตอรี่แล้วเพื่อยืดอายุการใช้งานแบตเตอรี่"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ภาพลักษณ์ของแบรนด์แอปพลิเคชัน"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"ตรวจสอบการตั้งค่าการเข้าถึง"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> จะดูและควบคุมหน้าจอของคุณได้ แตะเพื่อตรวจสอบ"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index c2409c4f41f6..3e3289bae412 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Hindi alam na portrait"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Hindi alam na landscape"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Kinansela"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Na-update ng iyong admin"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Na-delete ng iyong admin"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Ino-on ng Pantipid ng Baterya ang Madilim na tema at nililimitahan o ino-off nito ang aktibidad sa background, ilang visual effect, at ilang partikular na feature.\n\n"<annotation id="url">"Matuto pa"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Ino-on ng Pantipid ng Baterya ang Madilim na tema at nililimitahan o ino-off nito ang aktibidad sa background, ilang visual effect, at ilang partikular na feature."</string> <string name="data_saver_description" msgid="4995164271550590517">"Upang makatulong na mabawasan ang paggamit ng data, pinipigilan ng Data Saver ang ilang app na magpadala o makatanggap ng data sa background. Maaaring mag-access ng data ang isang app na ginagamit mo sa kasalukuyan, ngunit mas bihira na nito magagawa iyon. Halimbawa, maaaring hindi lumabas ang mga larawan hangga\'t hindi mo nata-tap ang mga ito."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"I-on ang Data Saver?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"I-on"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Na-demote sa Naka-silent ang notification na ito. I-tap para magbigay ng feedback."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Itinaas ang ranggo ng notification na ito. I-tap para magbigay ng feedback."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Ibinaba ang ranggo ng notification na ito. I-tap para magbigay ng feedback."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Subukan ang enhanced notification"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Para patuloy na makakuha ng mga iminumungkahing pagkilos, sagot, at higit pa, i-on ang mga pinahusay na notification. Hindi na sinusuportahan ang Mga Adaptive na Notification ng Android."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"I-on"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Hindi ngayon"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Mga pinahusay na notification"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Nagbibigay na ng mga iminumungkahing pagkilos at tugon ang mga pinahusay na notification. Hindi na sinusuportahan ang Mga Adaptive na Notification ng Android."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"I-off"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Matuto pa"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Puwedeng basahin ng mga pinahusay na notification ang lahat ng notification, kabilang ang personal na impormasyon gaya ng mga pangalan ng contact at mga mensahe. Magagawa ring ng feature na ito na i-dismiss ang mga notification o gumawa ng mga pagkilos sa mga button sa mga notification, gaya ng pagsagot sa mga tawag sa telepono.\n\nPuwede ring i-on o i-off ng feature na ito ang Priority mode at baguhin ang mga kaugnay na setting."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Pinalitan ng mga pinahusay na notification ang Mga Adaptive na Notification ng Android sa Android 12. Nagpapakita ng mga iminumungkahing pagkilos at tugon ang feature na ito, at isinasaayos nito ang iyong mga notification.\n\nMaa-access ng mga pinahusay na notification ang content ng notification, kabilang ang personal na impormasyon gaya ng mga pangalan ng contact at mensahe. Puwede ring i-dismiss o tugunan ng feature na ito ang mga notification, gaya ng pagsagot sa mga tawag at pagkontrol sa Huwag Istorbohin."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification ng impormasyon ng Routine Mode"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Maaaring maubos ang baterya bago ang karaniwang pag-charge"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Na-activate ang Pantipid ng Baterya para patagalin ang buhay ng baterya"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Representasyon ng brand ng application"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Tingnan ang mga setting ng pag-access"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"Makikita at makokontrol ng <xliff:g id="SERVICE_NAME">%s</xliff:g> ang iyong screen. I-tap para suriin."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 935e489cb8ad..3f1fb4ab944a 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Bilinmeyen dikey"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Bilinmeyen yatay"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"İptal edildi"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Yöneticiniz tarafından güncellendi"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Yöneticiniz tarafından silindi"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Tamam"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Pil Tasarrufu özelliği Koyu temayı açıp arka plan etkinliğini, bazı görsel efektleri ve belirli özellikleri sınırlandırır ya da kapatır.\n\n"<annotation id="url">"Daha fazla bilgi"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Pil Tasarrufu özelliği Koyu temayı açıp arka plan etkinliğini, bazı görsel efektleri ve belirli özellikleri sınırlandırır ya da kapatır."</string> <string name="data_saver_description" msgid="4995164271550590517">"Veri kullanımını azaltmaya yardımcı olması için Veri Tasarrufu, bazı uygulamaların arka planda veri göndermesini veya almasını engeller. Kullanmakta olduğunuz bir uygulama veri bağlantısına erişebilir, ancak bunu daha seyrek yapabilir. Bu durumda örneğin, siz resimlere dokunmadan resimler görüntülenmez."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Veri Tasarrufu açılsın mı?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Aç"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Bu bildirimin önem derecesi, \"Sessiz\" seviyesine düşürüldü. Geri bildirimde bulunmak için dokunun."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Bu bildirimin önem derecesi yükseltildi. Geri bildirimde bulunmak için dokunun."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Bu bildirimin önem derecesi düşürüldü. Geri bildirimde bulunmak için dokunun."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Gelişmiş bildirimleri deneyin"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Önerilen işlemleri, yanıtları ve diğer içerikleri almaya devam etmek için gelişmiş bildirimleri açın. Android Uyarlamalı Bildirimler artık desteklenmiyor."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Aç"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Şimdi değil"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Gelişmiş bildirimler"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Önerilen işlemler ve yanıtlar artık gelişmiş bildirimler tarafından sağlanıyor. Android Uyarlamalı Bildirimler artık desteklenmiyor."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Tamam"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Kapat"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Daha fazla bilgi"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Gelişmiş bildirimler, kişiler ve mesajlar gibi kişisel bilgiler dahil olmak üzere tüm bildirim içeriklerini okuyabilir. Bu özellik ayrıca bildirimleri kapatabilir veya bildirimlerdeki düğmeler üzerinde telefon çağrılarını yanıtlamak gibi işlemler yapabilir.\n\nBu özellik ayrıca Öncelik modunu açıp kapatabilir ve ilgili ayarları değiştirebilir."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Gelişmiş bildirimler, Android 12\'de Android Uyarlamalı Bildirimler\'in yerini aldı. Bu özellik, önerilen işlem ve yanıtları gösterir ve bildirimlerinizi organize eder.\n\nGelişmiş bildirimler, kişiler ve mesajlar gibi kişisel bilgiler dahil olmak üzere tüm bildirim içeriklerine erişebilir. Bu özellik ayrıca bildirimleri kapatabilir veya telefon aramalarını yanıtlamak ve Rahatsız Etmeyin modunu kontrol etmek gibi işlemlerle bildirimlere yanıt verebilir."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutin Modu bilgi bildirimi"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Pil normal şarjdan önce bitebilir"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Pilin ömrünü uzatmak için Pil Tasarrufu etkinleştirildi"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Uygulama marka imajı"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Erişim ayarlarını kontrol edin"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g>, ekranınızı görüntüleyip kontrol edebilir. İncelemek için dokunun."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index ca3b5899e5f4..b479ec849157 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1817,28 +1817,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch (Пн. Америка)"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto (Пн. Америка)"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap (Пн. Америка)"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K (Китай)"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K (Китай)"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1 (Китай)"</string> @@ -1875,8 +1864,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu (Японія)"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2 (Японія)"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4 (Японія)"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Невідома книжкова орієнтація"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Невідома альбомна орієнтація"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Скасовано"</string> @@ -1922,10 +1910,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Оновлено адміністратором"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Видалено адміністратором"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"У режимі енергозбереження вмикається темна тема й обмежуються чи вимикаються фонова робота додатків, деякі візуальні ефекти та певні функції.\n\n"<annotation id="url">"Докладніше"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"У режимі енергозбереження вмикається темна тему й обмежуються чи вимикаються фонова робота додатків, деякі візуальні ефекти та певні функції."</string> <string name="data_saver_description" msgid="4995164271550590517">"Щоб зменшити використання трафіку, функція \"Заощадження трафіку\" не дозволяє деяким додаткам надсилати чи отримувати дані у фоновому режимі. Поточний додаток зможе отримувати доступ до таких даних, але рідше. Наприклад, зображення не відображатиметься, доки ви не торкнетеся його."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Увімкнути заощадження трафіку?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Увімкнути"</string> @@ -2165,12 +2151,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Важливість цього сповіщення знижено до рівня \"Без звуку\". Натисніть, щоб надіслати відгук."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Важливість цього сповіщення підвищено. Натисніть, щоб надіслати відгук."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Важливість цього сповіщення знижено. Натисніть, щоб надіслати відгук."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Спробуйте покращені сповіщення"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Щоб і надалі отримувати пропозиції дій, відповідей тощо, увімкніть покращені сповіщення. Адаптивні сповіщення Android більше не підтримуються."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Увімкнути"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Не зараз"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Покращені сповіщення"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Тепер пропоновані дії та відповіді можна знайти в покращених сповіщеннях. Адаптивні сповіщення Android більше не підтримуються."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Вимкнути"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Докладніше"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Покращені сповіщення дають змогу читати весь вміст сповіщень, зокрема особисту інформацію, як-от імена контактів і повідомлення. Крім того, ви зможете відхиляти сповіщення або натискати кнопки в них, щоб виконувати певні дії, наприклад відповідати на телефонні дзвінки.\n\nЦя функція також дає змогу вмикати й вимикати режим пріоритетності та змінювати відповідні налаштування."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"У версії ОС Android 12 адаптивні сповіщення замінено на покращені. Ця функція допомагає впорядковувати сповіщення й показує в них пропоновані дії та відповіді.\n\nПокращені сповіщення надають доступ до вмісту сповіщень, зокрема до особистої інформації, наприклад повідомлень та імен контактів. Ця функція може автоматично відхиляти сповіщення чи реагувати на них, наприклад відповідати на телефонні дзвінки або керувати режимом \"Не турбувати\"."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Сповіщення про послідовнсть дій"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Акумулятор може розрядитися раніше ніж зазвичай"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Режим енергозбереження активовано для збільшення часу роботи акумулятора"</string> @@ -2369,4 +2355,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Зображення фірмової символіки додатка"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Перевірте налаштування доступу"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> може переглядати екран вашого пристрою та керувати ним. Натисніть, щоб переглянути."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 88786165f18e..48208ac677cc 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"مونارک"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"کوارٹو"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"فل اسکیپ"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"نامعلوم پورٹریٹ"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"نامعلوم لینڈ اسکیپ"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"منسوخ کر دیا گیا"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"آپ کے منتظم کے ذریعے اپ ڈیٹ کیا گیا"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ٹھیک ہے"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"بیٹری سیور گہری تھیم کو آن کرتی ہے اور پس منظر کی سرگرمی، کچھ بصری اثرات اور کچھ مخصوص خصوصیات کو محدود یا آف کرتی ہے۔\n\n"<annotation id="url">"مزید جانیں"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"بیٹری سیور گہری تھیم کو آن کرتی ہے اور پس منظر کی سرگرمی، کچھ بصری اثرات اور کچھ مخصوص خصوصیات کو محدود یا آف کرتی ہے۔"</string> <string name="data_saver_description" msgid="4995164271550590517">"ڈیٹا کے استعمال کو کم کرنے میں مدد کیلئے، ڈیٹا سیور پس منظر میں کچھ ایپس کو ڈیٹا بھیجنے یا موصول کرنے سے روکتی ہے۔ آپ جو ایپ فی الحال استعمال کر رہے ہیں وہ ڈیٹا تک رسائی کر سکتی ہے مگر ہو سکتا ہے ایسا اکثر نہ ہو۔ اس کا مطلب مثال کے طور پر یہ ہو سکتا ہے کہ تصاویر تھپتھپانے تک ظاہر نہ ہوں۔"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ڈیٹا سیور آن کریں؟"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"آن کریں"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"اس اطلاع کو خاموش پر ڈیموٹ کیا گيا۔ تاثرات فراہم کرنے کے ليے تھپتھپائیں۔"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"اس اطلاع کو اعلی درجہ دیا گیا۔ تاثرات فراہم کرنے کے ليے تھپتھپائیں۔"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"اس اطلاع کو کم درجہ دیا گیا۔ تاثرات فراہم کرنے کے ليے تھپتھپائیں۔"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"بہتر کردہ اطلاعات آزمائیں"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"تجویز کردہ کارروائیاں، جوابات اور مزید بہت کچھ حاصل کرنا جاری رکھنے کے لیے بہتر کردہ اطلاعات آن کریں۔ Android اڈاپٹیو اطلاعات اب تعاون یافتہ نہیں ہیں۔"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"آن کریں"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"ابھی نہیں"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"بہتر کردہ اطلاعات"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"تجویز کردہ کارروائیاں اور جوابات اب بہتر اطلاعات کے ذریعے فراہم کیے جاتے ہیں۔ Android اڈاپٹیو کی اطلاعات اب تعاون یافتہ نہیں ہیں۔"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ٹھیک ہے"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"آف کریں"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"مزید جانیں"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"بہتر کردہ اطلاعات رابطوں کے نام اور پیغامات جیسی ذاتی معلومات سمیت تمام اطلاعی مواد پڑھ سکتی ہیں۔ یہ خصوصیت اطلاعات کو برخاست بھی کر سکتی ہے یا کالز کا جواب دینے جیسے اطلاعات میں نظر آنے والے بٹنوں سے کارروائیاں کر سکتی ہے۔\n\nیہ خصوصیت ترجیحی موڈ کو آن یا آف بھی کر سکتی ہے اور متعلقہ ترتیبات کو تبدیل کر سکتی ہے۔"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 میں بہتر کردہ اطلاعات کو Android اڈاپٹیو کی اطلاعات سے تبدیل کیا گیا ہے۔ یہ خصوصیت تجویز کردہ کارروائیاں اور جوابات دکھاتی ہے اور آپ کی اطلاعات کا نظم کرتی ہے۔\n\nبہتر کردہ اطلاعات رابطوں کے نام اور پیغامات جیسی ذاتی معلومات سمیت اطلاعات کے مواد تک رسائی حاصل کر سکتی ہیں۔ یہ خصوصیت اطلاعات کو برخاست کر سکتی ہے یا اس کا جواب بھی دے سکتی ہے جیسے فون کالز کا جواب دینا اور ڈسٹرب نہ کریں کو کنٹرول کرنا۔"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"روٹین موڈ معلومات کی اطلاع"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"معمول چارج سے پہلے بیٹری ختم ہو سکتی ہے"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"بیٹری لائف کو بڑھانے کے لیے بیٹری سیور کو فعال کر دیا گیا ہے"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ایپلیکیشن کی برانڈنگ تصویر"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"رسائی کی ترتیبات چیک کریں"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> آپ کی اسکرین کو دیکھ اور کنٹرول کر سکتی ہیں۔ جائزے کے لیے تھپتھپائیں۔"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 90bbd47b02a1..4c690306e924 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -1708,7 +1708,7 @@ <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Tezkor ishga tushirishni o‘chirib qo‘yish"</string> <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="color_correction_feature_name" msgid="3655077237805422597">"Ranglarni tuzatish"</string> <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Juda xira"</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> @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarx"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Noma’lum bo‘yiga"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Noma’lum eniga"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Bekor qilindi"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Administrator tomonidan yangilangan"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administrator tomonidan o‘chirilgan"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Quvvat tejash tungi mavzuni yoqadi va orqa fondagi harakatlar, ayrim vizual effektlar va ayrim funksiyalarni cheklaydi yoki oʻchiradi.\n\n"<annotation id="url">"Batafsil"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Quvvat tejash tungi mavzuni yoqadi va orqa fondagi harakatlar, ayrim vizual effektlar va ayrim funksiyalarni cheklaydi yoki oʻchiradi."</string> <string name="data_saver_description" msgid="4995164271550590517">"Trafik tejash rejimida ayrim ilovalar uchun orqa fonda internetdan foydalanish imkoniyati cheklanadi. Siz ishlatayotgan ilova zaruratga qarab internet-trafik sarflashi mumkin, biroq cheklangan miqdorda. Masalan, rasmlar ustiga bosmaguningizcha ular yuklanmaydi."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Trafik tejash yoqilsinmi?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Yoqish"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Bu bildirishnoma darajasi Tovushsiz darajaga tushirildi Fikr-mulohaza bildirish uchun bosing."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Bu bildirishnoma darajasi oshirildi. Fikr-mulohaza bildirish uchun bosing."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Bu bildirishnoma darajasi pasaytirildi. Fikr-mulohaza bildirish uchun bosing."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Yangicha bildirishnomalar"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Amallar, javoblar va boshqa takliflarni olishda davom etish uchun yaxshilangan bildirishnomalarni yoqing. Android moslashuvchan bildirishnomalari endi ishlamaydi."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Yoqish"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Hozir emas"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Yangicha bildirishnomalar"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Amallar va javoblar taklifi endi yangicha bildirishnomalar orqali chiqadi. Android moslashuvchan bildirishnomalari endi ishlamaydi."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Faolsizlantirish"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Batafsil"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Yangicha bildirishnomalar funksiyasi barcha bildirishnomalarni, jumladan, shaxsiy maʼlumotlarni (kontakt nomlari va xabarlar) oʻqiy oladi. Shuningdek, bu funksiya bildirishnomalarni yopishi yoki telefon chaqiruvlariga javob berish kabi bildirishnomalarda tugmalar bilan amallar bajarishi mumkin.\n\nBu funksiya Faqat muhim rejimini yoqishi va faolsizlantirishi yoki unga aloqador sozlamalarni oʻzgartirishi ham mumkin."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Android 12 tizimida moslashuvchan bildirishnomalar oʻrniga yangicha bildirishnomalar chiqadi. Bu funksiya amallar va javoblarni taklif qiladi va bildirishnomalaringizni boshqaradi.\n\nYangicha bildirishnomalar barcha bildirishnomalar kontentini, jumladan kontakt nomlari va xabarlar kabi shaxsiy bildirishnomalarni ham oʻqiy oladi. Shuningdek, bu funksiya bildirishnomalarni yopishi yoki telefon chaqiruvlariga javob berishi va Bezovta qilinmasin rejimini boshqarishi mumkin."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Kun tartibi rejimi haqidagi bildirishnoma"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batareya quvvati odatdagidan ertaroq tugashi mumkin"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batareya quvvatini uzoqroq vaqtga yetkazish uchun quvvat tejash rejimi yoqildi"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Ilova brendining rasmi"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Ruxsat sozlamalarini tekshiring"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ekraningizni koʻrishi va boshqarishi mumkin. Tekshirish uchun bosing."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 44247332d037..74b3846f5b28 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Giấy khổ rộng"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Khổ dọc không xác định"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Khổ ngang không xác định"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Đã hủy"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Do quản trị viên của bạn cập nhật"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Do quản trị viên của bạn xóa"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Tính năng Tiết kiệm pin sẽ bật Giao diện tối, đồng thời hạn chế hoặc tắt hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng nhất định.\n\n"<annotation id="url">"Tìm hiểu thêm"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Tính năng Tiết kiệm pin sẽ bật Giao diện tối, đồng thời hạn chế hoặc tắt hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng nhất định."</string> <string name="data_saver_description" msgid="4995164271550590517">"Để giúp giảm mức sử dụng dữ liệu, Trình tiết kiệm dữ liệu sẽ chặn một số ứng dụng gửi hoặc nhận dữ liệu trong nền. Ứng dụng mà bạn hiện sử dụng có thể dùng dữ liệu nhưng tần suất sẽ giảm. Ví dụ: hình ảnh sẽ không hiển thị cho đến khi bạn nhấn vào hình ảnh đó."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Bật Trình tiết kiệm dữ liệu?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Bật"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Hệ thống đã hạ mức ưu tiên của thông báo này xuống thành Im lặng. Hãy nhấn để chia sẻ ý kiến phản hồi."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Hệ thống đã nâng mức ưu tiên của thông báo này. Hãy nhấn để chia sẻ ý kiến phản hồi."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Hệ thống đã hạ mức ưu tiên của thông báo này. Hãy nhấn để chia sẻ ý kiến phản hồi."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Dùng thử thông báo nâng cao"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Để tiếp tục nhận các thao tác đề xuất, câu trả lời và nhiều nội dung khác, hãy bật thông báo nâng cao. Thông báo thích ứng trên Android không được hỗ trợ nữa."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Bật"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Để sau"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Thông báo nâng cao"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Thông báo nâng cao hiện cung cấp các thao tác và câu trả lời đề xuất. Thông báo thích ứng trên Android không được hỗ trợ nữa."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Tắt"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Tìm hiểu thêm"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Thông báo nâng cao có thể đọc mọi nội dung thông báo, bao gồm cả thông tin cá nhân như tên liên hệ và tin nhắn. Tính năng này cũng có thể đóng các thông báo hoặc thực hiện thao tác đối với các nút trong thông báo, chẳng hạn như trả lời cuộc gọi điện thoại.\n\nTính năng này cũng có thể bật hoặc tắt Chế độ ưu tiên và thay đổi các chế độ cài đặt liên quan."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Thông báo nâng cao đã thay thế Thông báo thích ứng trên Android trong Android 12. Tính năng này hiển thị những thao tác và câu trả lời đề xuất, đồng thời sắp xếp các thông báo của bạn.\n\nThông báo nâng cao có thể đọc mọi nội dung thông báo, bao gồm cả thông tin cá nhân như tên liên hệ và tin nhắn. Tính năng này cũng có thể đóng hoặc phản hồi các thông báo, chẳng hạn như trả lời cuộc gọi điện thoại và điều khiển chế độ Không làm phiền."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Thông báo cung cấp thông tin về chế độ sạc thông thường"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Pin có thể hết trước khi sạc bình thường"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Trình tiết kiệm pin được kích hoạt để kéo dài thời lượng pin"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Hình ảnh thương hiệu của ứng dụng"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Hãy kiểm tra chế độ cài đặt quyền truy cập"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> có thể xem và điều khiển màn hình của bạn. Nhấn để xem lại."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 2ffca206106e..3122053aca0b 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"大"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"未知(纵向)"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"未知(横向)"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"已取消"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理员更新"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"已由您的管理员删除"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"确定"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"在省电模式下,系统会启用深色主题,并限制或关闭后台活动、部分视觉效果和某些功能。\n\n"<annotation id="url">"了解详情"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"在省电模式下,系统会启用深色主题,并限制或关闭后台活动、部分视觉效果和某些功能。"</string> <string name="data_saver_description" msgid="4995164271550590517">"为了减少流量消耗,流量节省程序会阻止某些应用在后台收发数据。您当前使用的应用可以收发数据,但频率可能会降低。举例而言,这可能意味着图片只有在您点按之后才会显示。"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"要开启流量节省程序吗?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"开启"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"系统已将此通知的重要性降低为“静音”。点按即可提供反馈。"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"系统已提升此通知的重要性。点按即可提供反馈。"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"系统已降低此通知的重要性。点按即可提供反馈。"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"试用增强型通知"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"如需继续接收建议的操作、回复等内容,请开启增强型通知功能。系统不再支持 Android 自动调节通知功能。"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"开启"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"以后再说"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"增强型通知功能"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"建议的操作和回复目前由增强型通知功能提供。系统不再支持 Android 自适应通知功能。"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"确定"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"关闭"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"了解详情"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"增强型通知功能可以读取所有通知内容,包括联系人姓名和消息等个人信息。该功能也能关闭通知或触发通知中的按钮,例如接听来电。\n\n此外,该功能还能开启或关闭“优先”模式,以及更改相关设置。"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"在 Android 12 中,增强型通知功能取代了 Android 自适应通知功能。增强型通知功能可以显示建议的操作和回复,并可将通知整理得井井有条。\n\n增强型通知功能可以访问通知内容,包括联系人名称和消息等个人信息。该功能还可以关闭或响应通知,例如接听来电以及控制勿扰模式。"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式信息通知"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"电池电量可能会在您平时的充电时间之前耗尽"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已启用省电模式以延长电池续航时间"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"应用品牌图片"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"查看权限设置"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g>可以查看和控制您的屏幕。点按即可查看。"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 30619859af87..1597477c5d1a 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1820,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"不明直向紙張"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"不明橫向紙張"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"已取消"</string> @@ -1865,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理員更新"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"已由您的管理員刪除"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"好"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"「省電模式」會開啟深色主題背景,並限制或關閉背景活動、部分視覺效果和特定功能。\n\n"<annotation id="url">"瞭解詳情"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"「省電模式」會開啟深色主題背景,並限制或關閉背景活動、部分視覺效果和特定功能。"</string> <string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。您正在使用的應用程式可存取資料,但次數可能會減少。例如,圖片可能需要輕按才會顯示。"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟「數據節省模式」嗎?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"開啟"</string> @@ -2088,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"此通知的重要性已降低為「靜音」。輕按即可提供意見。"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"此通知的重要性已提升。輕按即可提供意見。"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"此通知的重要性已降級。輕按即可提供意見。"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"試用強化通知"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"如要繼續收到建議操作和回覆等內容,請開啟強化通知功能。系統已不再支援 Android 自動調整通知功能。"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"開啟"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"暫時不要"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"強化通知"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"建議的操作和回覆目前由強化通知功能提供。系統已不再支援 Android 自動調整通知功能。"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"確定"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"關閉"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"瞭解詳情"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"強化通知功能可讀取所有通知內容 (包括聯絡人姓名和訊息等個人資料),以及關閉通知或針對通知中的按鈕採取行動,例如接聽來電。\n\n此功能亦可開啟或關閉「優先」模式及變更相關設定。"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"在 Android 12 中,我們將 Android 自動調整通知取代成強化通知。此功能可顯示建議操作和回覆,以及整理通知。\n\n強化通知功能可讀取所有通知內容 (包括聯絡人姓名和訊息等個人資料),以及關閉或回應通知,例如接聽來電和控制「請勿騷擾」功能。"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"「日常安排模式」資料通知"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"電量可能會在日常充電前耗盡"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"「省電模式」已啟用,以便延長電池壽命"</string> @@ -2290,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"應用程式品牌形象"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"檢查存取權設定"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> 可以查看及控制您的螢幕。輕按即可查看。"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 6239b51fcd65..7d02173248ce 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"不明縱向紙張"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"不明橫向紙張"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"已取消"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"確定"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"省電模式會開啟深色主題,並限制或關閉背景活動、某些視覺效果和特定功能。\n\n"<annotation id="url">"瞭解詳情"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"省電模式會開啟深色主題,並限制或關閉背景活動、某些視覺效果和特定功能。"</string> <string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,在你輕觸後才會顯示。"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟數據節省模式嗎?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"開啟"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"這則通知的重要性已降低為「靜音」。輕觸即可提供意見。"</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"這則通知的重要性順序已調高。輕觸即可提供意見。"</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"這則通知的重要性順序已調降。輕觸即可提供意見。"</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"試試看加強型通知"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"如要繼續收到建議的操作、回覆等內容,請開啟加強型通知功能。系統已不再支援 Android 自動調整通知功能。"</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"開啟"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"暫時不要"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"加強型通知"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"建議的操作和回覆內容目前是由加強型通知功能提供。系統已不再支援 Android 自動調整通知功能。"</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"確定"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"關閉"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"瞭解詳情"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"加強型通知功能可讀取所有通知內容,包括聯絡人名稱和訊息內文等個人資訊。這項功能也能關閉通知或操作通知中的按鈕,例如接聽來電。\n\n此外,這項功能還可以開啟或關閉「優先」模式及變更相關設定。"</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"在 Android 12 中,加強型通知功能已取代 Android 自動調整通知。這項功能可以顯示建議的操作和回覆內容,也可以整理通知。\n\n加強型通知功能可存取通知內容,包括聯絡人名稱和訊息內文等個人資訊。此外,這項功能還能關閉或回覆通知,例如接聽來電及控管「零打擾」功能。"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式資訊通知"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"電池電力可能會在你平常的充電時間前耗盡"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已啟用省電模式以延長電池續航力"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"應用程式品牌圖片"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"查看存取權設定"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"「<xliff:g id="SERVICE_NAME">%s</xliff:g>」可以查看及控管你的螢幕。輕觸即可查看。"</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 18481fce4181..f68a7aa44719 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -1773,28 +1773,17 @@ <string name="mediasize_na_monarch" msgid="4396943937986136896">"I-Monarch"</string> <string name="mediasize_na_quarto" msgid="2119101847712239885">"I-Quarto"</string> <string name="mediasize_na_foolscap" msgid="5011612828564394648">"I-Foolscap"</string> - <!-- no translation found for mediasize_na_ansi_c (3104916921818289618) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_d (254005964819282724) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_e (4424174989686785675) --> - <skip /> - <!-- no translation found for mediasize_na_ansi_f (146980362213260987) --> - <skip /> - <!-- no translation found for mediasize_na_arch_a (5280681822380032361) --> - <skip /> - <!-- no translation found for mediasize_na_arch_b (2113344093437297427) --> - <skip /> - <!-- no translation found for mediasize_na_arch_c (971002546186856623) --> - <skip /> - <!-- no translation found for mediasize_na_arch_d (6450996075335049806) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e (6782708486949266519) --> - <skip /> - <!-- no translation found for mediasize_na_arch_e1 (4707138568738504275) --> - <skip /> - <!-- no translation found for mediasize_na_super_b (6964127155618393178) --> - <skip /> + <string name="mediasize_na_ansi_c" msgid="3104916921818289618">"ANSI C"</string> + <string name="mediasize_na_ansi_d" msgid="254005964819282724">"ANSI D"</string> + <string name="mediasize_na_ansi_e" msgid="4424174989686785675">"ANSI E"</string> + <string name="mediasize_na_ansi_f" msgid="146980362213260987">"ANSI F"</string> + <string name="mediasize_na_arch_a" msgid="5280681822380032361">"Arch A"</string> + <string name="mediasize_na_arch_b" msgid="2113344093437297427">"Arch B"</string> + <string name="mediasize_na_arch_c" msgid="971002546186856623">"Arch C"</string> + <string name="mediasize_na_arch_d" msgid="6450996075335049806">"Arch D"</string> + <string name="mediasize_na_arch_e" msgid="6782708486949266519">"Arch E"</string> + <string name="mediasize_na_arch_e1" msgid="4707138568738504275">"Arch E1"</string> + <string name="mediasize_na_super_b" msgid="6964127155618393178">"Super-B"</string> <string name="mediasize_chinese_roc_8k" msgid="411670106572707544">"I-ROC 8K"</string> <string name="mediasize_chinese_roc_16k" msgid="7496706798725321898">"I-ROC 16K"</string> <string name="mediasize_chinese_prc_1" msgid="946949835711037253">"I-PRC 1"</string> @@ -1831,8 +1820,7 @@ <string name="mediasize_japanese_kahu" msgid="7290232592648122042">"I-Kahu"</string> <string name="mediasize_japanese_kaku2" msgid="7477551750461028312">"I-Kaku2"</string> <string name="mediasize_japanese_you4" msgid="5552111912684384833">"I-You4"</string> - <!-- no translation found for mediasize_japanese_l (1326765321473431817) --> - <skip /> + <string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string> <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Ukuma ngobude obungaziwa"</string> <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Ukwakheka kwezwe okungaziwa"</string> <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Kukhanseliwe"</string> @@ -1876,10 +1864,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Kubuyekezwe umlawuli wakho"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Kususwe umlawuli wakho"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"KULUNGILE"</string> - <!-- no translation found for battery_saver_description_with_learn_more (750683025714899363) --> - <skip /> - <!-- no translation found for battery_saver_description (5693741424234005958) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="750683025714899363">"Isilondolozi Sebhethri sivula Itimu emnyama futhi silinganise noma sivale umsebenzi ongemuva, imiphumela ethile yokubuka, nezakhi ezithile.\n\n"<annotation id="url">"Funda kabanzi"</annotation></string> + <string name="battery_saver_description" msgid="5693741424234005958">"Isilondolozi Sebhethri sivula itimu emnyama futhi silinganise noma sivale umsebenzi ongemuva, imiphumela ethile yokubuka, nezakhi ezithile."</string> <string name="data_saver_description" msgid="4995164271550590517">"Ukusiza ukwehlisa ukusetshenziswa kwedatha, iseva yedatha igwema ezinye izinhlelo zokusebenza ukuthi zithumele noma zamukele idatha ngasemuva. Uhlelo lokusebenza olisebenzisa okwamanje lingafinyelela idatha, kodwa lingenza kanjalo kancane. Lokhu kungachaza, isibonelo, ukuthi izithombe azibonisi uze uzithephe."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Vula iseva yedatha?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Vula"</string> @@ -2099,12 +2085,12 @@ <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Lesi saziso sehliselwe esikhundleni Sokuthula. Thepha ukuze unikeze impendulo."</string> <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Lesi saziso sibekwe ezingeni eliphakeme. Thepha ukuze unikeze impendulo."</string> <string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Lesi saziso sibekwe ezingeni eliphansi. Thepha ukuze unikeze impendulo."</string> - <string name="nas_upgrade_notification_title" msgid="4224351129445073051">"Zama izaziso ezigqanyisiwe"</string> - <string name="nas_upgrade_notification_content" msgid="7036860187157134706">"Ukuze uqhubeke nokuthola izenzo eziphakanyisiwe, izimpendulo nokuningi, vula izaziso ezigqanyisiwe. Izaziso ze-Androin Ezivumelana Nezimo azisasekelwe."</string> - <string name="nas_upgrade_notification_enable_action" msgid="4823652531622744798">"Vula"</string> - <string name="nas_upgrade_notification_disable_action" msgid="7561210256700811433">"Hhayi manje"</string> + <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Izaziso ezigqanyisiwe"</string> + <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"Izenzo nezimpendulo eziphakanyisiwe manje sezihlinzekwa ngezaziso ezithuthukisiwe. Izaziso ze-Androin Ezivumelana Nezimo azisasekelwe."</string> + <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"KULUNGILE"</string> + <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Vala"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Funda kabanzi"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="6276343083934111208">"Izaziso ezigqanyisiwe zingafunda konke okuqukethwe yizaziso zakho, kuhlanganise nolwazi lomuntu siqu njengamagama oxhumana nabo nemilayezo. Lesi sakhi singacashisa izaziso noma sithathe izinyathelo ezinkinobheni ezisezazisweni, njengokuphendula amakholi wefoni.\n\nLesi sici singavula noma sivale nemodi Yokubalulekile futhi sishintshe amasethingi ahambisanayo."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="2353549817159426430">"Izaziso ezithuthukisiwe zithathe isikhundla sezaziso eziguqukayo ze-Android ku-Android 12. Lesi sici sikhombisa izenzo eziphakanyisiwe nezimpendulo, futhi sihlela izaziso zakho.\n\nIzaziso ezithuthukisiwe zingafinyelela kokuqukethwe kwesaziso, kuhlanganise nemininingwane yomuntu efana namagama woxhumana nabo nemilayezo. Lesi sakhi singacashisa noma siphendule izaziso, njengokuphendula amakholi efoni nokulawula ukuthi Ungaphazamisi."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Isaziso solwazi lwe-Routine Mode"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Ibhethri lingaphela ngaphambi kokushaja okuvamile"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Isilondolozi sebhethri siyasebenza ngaphandle kwempilo yebhethri"</string> @@ -2301,4 +2287,8 @@ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Isithombe sokubhrenda i-application"</string> <string name="view_and_control_notification_title" msgid="4300765399209912240">"Hlola amasethingi wokufinyelela"</string> <string name="view_and_control_notification_content" msgid="8003766498562604034">"I-<xliff:g id="SERVICE_NAME">%s</xliff:g> ingakwazi ukubuka nokulawula isikrini sakho. Thepha ukuze ubuyekeze."</string> + <!-- no translation found for ui_translation_accessibility_translated_text (3197547218178944544) --> + <skip /> + <!-- no translation found for ui_translation_accessibility_translation_finished (3057830947610088465) --> + <skip /> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index f097009f9a6e..d4fa28531acd 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -9576,8 +9576,9 @@ <attr name="lStar" format="float"/> <declare-styleable name="DisplayHashingService"> - <!-- The throttle duration for display hash requests + <!-- The interval required between display hash requests. Requests made faster than this + delay will be throttled." @hide @SystemApi --> - <attr name="throttleDurationMillis" format="integer" /> + <attr name="durationBetweenRequestsMillis" format="integer" /> </declare-styleable> </resources> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 0213c60e9f60..36168e7bd937 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -427,4 +427,10 @@ <!-- Darkest shade of the secondary neutral color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_1000">#000000</color> + + <!-- Accessibility shortcut icon background color --> + <color name="accessibility_feature_background">#5F6368</color> <!-- Google grey 700 --> + <color name="accessibility_magnification_background">#F50D60</color> + <color name="accessibility_daltonizer_background">#00BCD4</color> + <color name="accessibility_color_inversion_background">#546E7A</color> </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 529aa6641c68..d3ea52eb8888 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -657,6 +657,12 @@ <!-- Indicate the display area rect for foldable devices in folded state. --> <string name="config_foldedArea"></string> + <!-- Indicates that the device supports having more than one internal display on at the same + time. Only applicable to devices with more than one internal display. If this option is + set to false, DisplayManager will make additional effort to ensure no more than 1 internal + display is powered on at the same time. --> + <bool name="config_supportsConcurrentInternalDisplays">true</bool> + <!-- Desk dock behavior --> <!-- The number of degrees to rotate the display when the device is in a desk dock. @@ -4854,17 +4860,30 @@ <!-- Whether app hibernation deletes OAT artifact files as part of global hibernation. --> <bool name="config_hibernationDeletesOatArtifactsEnabled">true</bool> - <!-- On-device intelligent processor for system UI features. --> + <!-- Package name of the on-device intelligent processor for system UI + features. Examples include the search functionality or the app + predictor. --> <string name="config_systemUiIntelligence" translatable="false"></string> - <!-- On-device intelligent processor for ambient audio. --> + <!-- Package name of the on-device intelligent processor for ambient audio. + Ambient audio is the sound surrounding the device captured by the DSP + or the microphone. In other words, the device is continuously + processing audio data in background. --> <string name="config_systemAmbientAudioIntelligence" translatable="false"></string> - <!-- On-device intelligent processor for audio. --> + <!-- Package name of the on-device intelligent processor for audio. The + difference of 'ambient audio' and 'audio' is that in 'audio', the + user intentionally and consciously aware that the device is recording + or using the microphone. + --> <string name="config_systemAudioIntelligence" translatable="false"></string> - <!-- On-device intelligent processor for notification. --> + <!-- Package name of the on-device intelligent processor for notification. + --> <string name="config_systemNotificationIntelligence" translatable="false"></string> - <!-- On-device intelligent processor for text. --> + <!-- Package name of the on-device intelligent processor for text. Examples + include providing autofill functionality based on incoming text + messages. --> <string name="config_systemTextIntelligence" translatable="false"></string> - <!-- On-device intelligent processor for visual features. --> + <!-- Package name of the on-device intelligent processor for visual + features. Examples include the autorotate feature. --> <string name="config_systemVisualIntelligence" translatable="false"></string> <!-- On-device package for providing companion device associations. --> <string name="config_systemCompanionDeviceProvider" translatable="false"></string> @@ -4873,4 +4892,7 @@ <bool name="config_supportsMicToggle">false</bool> <!-- Whether this device is supporting the camera toggle --> <bool name="config_supportsCamToggle">false</bool> + + <!-- List containing the allowed install sources for accessibility service. --> + <string-array name="config_accessibility_allowed_install_source" translatable="false"/> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 43c0ec979281..6be6167fba30 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -37,7 +37,7 @@ <!-- Text size of the message within a toast --> <dimen name="toast_text_size">14sp</dimen> <!-- Elevation of toast view --> - <dimen name="toast_elevation">6dp</dimen> + <dimen name="toast_elevation">2dp</dimen> <!-- Height of the status bar --> <dimen name="status_bar_height">@dimen/status_bar_height_portrait</dimen> @@ -367,6 +367,9 @@ <!-- The spacing between messages in Notification.MessagingStyle --> <dimen name="notification_messaging_spacing">6dp</dimen> + <!-- The spacing between messages in Notification.MessagingStyle --> + <dimen name="notification_messaging_spacing_conversation_group">24dp</dimen> + <!-- The rounding for messaging images --> <dimen name="messaging_image_rounding">4dp</dimen> @@ -573,6 +576,9 @@ <!-- Width of the outline stroke used by the accessibility focus rectangle --> <dimen name="accessibility_focus_highlight_stroke_width">4dp</dimen> + <!-- The padding ratio of the Accessibility icon foreground drawable --> + <item name="accessibility_icon_foreground_padding_ratio" type="dimen">21.88%</item> + <!-- Margin around the various security views --> <dimen name="keyguard_muliuser_selector_margin">8dp</dimen> @@ -760,7 +766,7 @@ <!-- The maximum size of the grayscale icon --> <dimen name="notification_grayscale_icon_max_size">256dp</dimen> - <dimen name="messaging_avatar_size">36dp</dimen> + <dimen name="messaging_avatar_size">48dp</dimen> <dimen name="conversation_avatar_size">48dp</dimen> <!-- start margin of the icon circle in the conversation's skin of the header --> <dimen name="conversation_icon_circle_start">28dp</dimen> @@ -779,17 +785,17 @@ <!-- size of the face pile icons --> <dimen name="conversation_face_pile_avatar_size">32dp</dimen> <!-- size of the face pile icons when the group is expanded --> - <dimen name="conversation_face_pile_avatar_size_group_expanded">25dp</dimen> + <dimen name="conversation_face_pile_avatar_size_group_expanded">@dimen/conversation_face_pile_avatar_size</dimen> <!-- Side margins of the conversation badge in relation to the conversation icon when the group is expanded--> - <dimen name="conversation_badge_side_margin_group_expanded">22dp</dimen> + <dimen name="conversation_badge_side_margin_group_expanded">@dimen/conversation_badge_side_margin</dimen> <!-- Side margins of the conversation badge in relation to the conversation icon when the group is expanded--> - <dimen name="conversation_badge_side_margin_group_expanded_face_pile">18dp</dimen> + <dimen name="conversation_badge_side_margin_group_expanded_face_pile">@dimen/conversation_badge_side_margin</dimen> <!-- The width of the protection of the face pile layout--> <dimen name="conversation_face_pile_protection_width">2dp</dimen> <!-- The width of the protection of the face pile layout when expanded--> - <dimen name="conversation_face_pile_protection_width_expanded">1dp</dimen> + <dimen name="conversation_face_pile_protection_width_expanded">@dimen/conversation_face_pile_protection_width</dimen> <!-- The padding of the expanded message container--> - <dimen name="expanded_group_conversation_message_padding">17dp</dimen> + <dimen name="expanded_group_conversation_message_padding">32dp</dimen> <!-- The stroke width of the ring used to visually mark a conversation as important --> <dimen name="importance_ring_stroke_width">2dp</dimen> <!-- The maximum stroke width used for the animation shown when a conversation is marked as important --> @@ -801,7 +807,7 @@ <dimen name="conversation_icon_container_top_padding">20dp</dimen> <!-- The top padding of the conversation icon container when the avatar is small--> - <dimen name="conversation_icon_container_top_padding_small_avatar">9dp</dimen> + <dimen name="conversation_icon_container_top_padding_small_avatar">8dp</dimen> <!-- The padding of the conversation header when expanded. This is calculated from the expand button size + notification_content_margin_end --> <dimen name="conversation_header_expanded_padding_end">38dp</dimen> diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml index 3c65caf074be..e9b42d392a2c 100644 --- a/core/res/res/values/locale_config.xml +++ b/core/res/res/values/locale_config.xml @@ -74,7 +74,7 @@ <item>ar-TD-u-nu-latn</item> <!-- Arabic (Chad, Western Digits) --> <item>ar-TN</item> <!-- Arabic (Tunisia) --> <item>ar-TN-u-nu-arab</item> <!-- Arabic (Tunisia, Arabic-Indic Digits) --> - <item>ar-XB</item> <!-- Right-to-left pseudolocale --> + <item>ar-XB</item> <!-- Arabic (Pseudo-Bidi) --> <item>ar-YE</item> <!-- Arabic (Yemen) --> <item>ar-YE-u-nu-latn</item> <!-- Arabic (Yemen, Western Digits) --> <item>as-IN</item> <!-- Assamese (India) --> @@ -104,6 +104,7 @@ <item>ca-FR</item> <!-- Catalan (France) --> <item>ca-IT</item> <!-- Catalan (Italy) --> <item>ce-RU</item> <!-- Chechen (Russia) --> + <item>ceb-PH</item> <!-- Cebuano (Philippines) --> <item>cgg-UG</item> <!-- Chiga (Uganda) --> <item>chr-US</item> <!-- Cherokee (United States) --> <item>cs-CZ</item> <!-- Czech (Czechia) --> @@ -119,15 +120,18 @@ <item>de-LI</item> <!-- German (Liechtenstein) --> <item>de-LU</item> <!-- German (Luxembourg) --> <item>dje-NE</item> <!-- Zarma (Niger) --> + <item>doi-IN</item> <!-- Dogri (India) --> <item>dsb-DE</item> <!-- Lower Sorbian (Germany) --> <item>dua-CM</item> <!-- Duala (Cameroon) --> <item>dyo-SN</item> <!-- Jola-Fonyi (Senegal) --> <item>dz-BT</item> <!-- Dzongkha (Bhutan) --> + <item>dz-BT-u-nu-latn</item> <!-- Dzongkha (Bhutan, Western Digits) --> <item>ebu-KE</item> <!-- Embu (Kenya) --> <item>ee-GH</item> <!-- Ewe (Ghana) --> <item>ee-TG</item> <!-- Ewe (Togo) --> <item>el-CY</item> <!-- Greek (Cyprus) --> <item>el-GR</item> <!-- Greek (Greece) --> + <item>en-AE</item> <!-- English (United Arab Emirates) --> <item>en-AG</item> <!-- English (Antigua & Barbuda) --> <item>en-AI</item> <!-- English (Anguilla) --> <item>en-AS</item> <!-- English (American Samoa) --> @@ -181,7 +185,7 @@ <item>en-LS</item> <!-- English (Lesotho) --> <item>en-MG</item> <!-- English (Madagascar) --> <item>en-MH</item> <!-- English (Marshall Islands) --> - <item>en-MO</item> <!-- English (Macau) --> + <item>en-MO</item> <!-- English (Macao) --> <item>en-MP</item> <!-- English (Northern Mariana Islands) --> <item>en-MS</item> <!-- English (Montserrat) --> <item>en-MT</item> <!-- English (Malta) --> @@ -212,7 +216,7 @@ <item>en-SL</item> <!-- English (Sierra Leone) --> <item>en-SS</item> <!-- English (South Sudan) --> <item>en-SX</item> <!-- English (Sint Maarten) --> - <item>en-SZ</item> <!-- English (Swaziland) --> + <item>en-SZ</item> <!-- English (Eswatini) --> <item>en-TC</item> <!-- English (Turks & Caicos Islands) --> <item>en-TK</item> <!-- English (Tokelau) --> <item>en-TO</item> <!-- English (Tonga) --> @@ -227,7 +231,7 @@ <item>en-VI</item> <!-- English (U.S. Virgin Islands) --> <item>en-VU</item> <!-- English (Vanuatu) --> <item>en-WS</item> <!-- English (Samoa) --> - <item>en-XA</item> <!-- Left-to-right pseudolocale --> + <item>en-XA</item> <!-- English (Pseudo-Accents) --> <item>en-ZA</item> <!-- English (South Africa) --> <item>en-ZM</item> <!-- English (Zambia) --> <item>en-ZW</item> <!-- English (Zimbabwe) --> @@ -265,10 +269,42 @@ <item>fa-AF-u-nu-latn</item> <!-- Persian (Afghanistan, Western Digits) --> <item>fa-IR</item> <!-- Persian (Iran) --> <item>fa-IR-u-nu-latn</item> <!-- Persian (Iran, Western Digits) --> - <item>ff-CM</item> <!-- Fulah (Cameroon) --> - <item>ff-GN</item> <!-- Fulah (Guinea) --> - <item>ff-MR</item> <!-- Fulah (Mauritania) --> - <item>ff-SN</item> <!-- Fulah (Senegal) --> + <item>ff-Adlm-BF</item> <!-- Fulah (Adlam, Burkina Faso) --> + <item>ff-Adlm-BF-u-nu-latn</item> <!-- Fulah (Adlam, Burkina Faso, Western Digits) --> + <item>ff-Adlm-CM</item> <!-- Fulah (Adlam, Cameroon) --> + <item>ff-Adlm-CM-u-nu-latn</item> <!-- Fulah (Adlam, Cameroon, Western Digits) --> + <item>ff-Adlm-GH</item> <!-- Fulah (Adlam, Ghana) --> + <item>ff-Adlm-GH-u-nu-latn</item> <!-- Fulah (Adlam, Ghana, Western Digits) --> + <item>ff-Adlm-GM</item> <!-- Fulah (Adlam, Gambia) --> + <item>ff-Adlm-GM-u-nu-latn</item> <!-- Fulah (Adlam, Gambia, Western Digits) --> + <item>ff-Adlm-GN</item> <!-- Fulah (Adlam, Guinea) --> + <item>ff-Adlm-GN-u-nu-latn</item> <!-- Fulah (Adlam, Guinea, Western Digits) --> + <item>ff-Adlm-GW</item> <!-- Fulah (Adlam, Guinea-Bissau) --> + <item>ff-Adlm-GW-u-nu-latn</item> <!-- Fulah (Adlam, Guinea-Bissau, Western Digits) --> + <item>ff-Adlm-LR</item> <!-- Fulah (Adlam, Liberia) --> + <item>ff-Adlm-LR-u-nu-latn</item> <!-- Fulah (Adlam, Liberia, Western Digits) --> + <item>ff-Adlm-MR</item> <!-- Fulah (Adlam, Mauritania) --> + <item>ff-Adlm-MR-u-nu-latn</item> <!-- Fulah (Adlam, Mauritania, Western Digits) --> + <item>ff-Adlm-NE</item> <!-- Fulah (Adlam, Niger) --> + <item>ff-Adlm-NE-u-nu-latn</item> <!-- Fulah (Adlam, Niger, Western Digits) --> + <item>ff-Adlm-NG</item> <!-- Fulah (Adlam, Nigeria) --> + <item>ff-Adlm-NG-u-nu-latn</item> <!-- Fulah (Adlam, Nigeria, Western Digits) --> + <item>ff-Adlm-SL</item> <!-- Fulah (Adlam, Sierra Leone) --> + <item>ff-Adlm-SL-u-nu-latn</item> <!-- Fulah (Adlam, Sierra Leone, Western Digits) --> + <item>ff-Adlm-SN</item> <!-- Fulah (Adlam, Senegal) --> + <item>ff-Adlm-SN-u-nu-latn</item> <!-- Fulah (Adlam, Senegal, Western Digits) --> + <item>ff-Latn-BF</item> <!-- Fulah (Latin, Burkina Faso) --> + <item>ff-Latn-CM</item> <!-- Fulah (Latin, Cameroon) --> + <item>ff-Latn-GH</item> <!-- Fulah (Latin, Ghana) --> + <item>ff-Latn-GM</item> <!-- Fulah (Latin, Gambia) --> + <item>ff-Latn-GN</item> <!-- Fulah (Latin, Guinea) --> + <item>ff-Latn-GW</item> <!-- Fulah (Latin, Guinea-Bissau) --> + <item>ff-Latn-LR</item> <!-- Fulah (Latin, Liberia) --> + <item>ff-Latn-MR</item> <!-- Fulah (Latin, Mauritania) --> + <item>ff-Latn-NE</item> <!-- Fulah (Latin, Niger) --> + <item>ff-Latn-NG</item> <!-- Fulah (Latin, Nigeria) --> + <item>ff-Latn-SL</item> <!-- Fulah (Latin, Sierra Leone) --> + <item>ff-Latn-SN</item> <!-- Fulah (Latin, Senegal) --> <item>fi-FI</item> <!-- Finnish (Finland) --> <item>fil-PH</item> <!-- Filipino (Philippines) --> <item>fo-DK</item> <!-- Faroese (Denmark) --> @@ -321,6 +357,7 @@ <item>fr-YT</item> <!-- French (Mayotte) --> <item>fur-IT</item> <!-- Friulian (Italy) --> <item>fy-NL</item> <!-- Western Frisian (Netherlands) --> + <item>ga-GB</item> <!-- Irish (United Kingdom) --> <item>ga-IE</item> <!-- Irish (Ireland) --> <item>gd-GB</item> <!-- Scottish Gaelic (United Kingdom) --> <item>gl-ES</item> <!-- Galician (Spain) --> @@ -340,6 +377,7 @@ <item>hsb-DE</item> <!-- Upper Sorbian (Germany) --> <item>hu-HU</item> <!-- Hungarian (Hungary) --> <item>hy-AM</item> <!-- Armenian (Armenia) --> + <item>ia-001</item> <!-- Interlingua (World) --> <item>ig-NG</item> <!-- Igbo (Nigeria) --> <item>ii-CN</item> <!-- Sichuan Yi (China) --> <item>in-ID</item> <!-- Indonesian (Indonesia) --> @@ -347,10 +385,12 @@ <item>it-CH</item> <!-- Italian (Switzerland) --> <item>it-IT</item> <!-- Italian (Italy) --> <item>it-SM</item> <!-- Italian (San Marino) --> + <item>it-VA</item> <!-- Italian (Vatican City) --> <item>iw-IL</item> <!-- Hebrew (Israel) --> <item>ja-JP</item> <!-- Japanese (Japan) --> <item>jgo-CM</item> <!-- Ngomba (Cameroon) --> <item>jmc-TZ</item> <!-- Machame (Tanzania) --> + <item>jv-ID</item> <!-- Javanese (Indonesia) --> <item>ka-GE</item> <!-- Georgian (Georgia) --> <item>kab-DZ</item> <!-- Kabyle (Algeria) --> <item>kam-KE</item> <!-- Kamba (Kenya) --> @@ -386,6 +426,7 @@ <item>luo-KE</item> <!-- Luo (Kenya) --> <item>luy-KE</item> <!-- Luyia (Kenya) --> <item>lv-LV</item> <!-- Latvian (Latvia) --> + <item>mai-IN</item> <!-- Maithili (India) --> <item>mas-KE</item> <!-- Masai (Kenya) --> <item>mas-TZ</item> <!-- Masai (Tanzania) --> <item>mer-KE</item> <!-- Meru (Kenya) --> @@ -393,23 +434,31 @@ <item>mg-MG</item> <!-- Malagasy (Madagascar) --> <item>mgh-MZ</item> <!-- Makhuwa-Meetto (Mozambique) --> <item>mgo-CM</item> <!-- Metaʼ (Cameroon) --> - <item>mk-MK</item> <!-- Macedonian (Macedonia (FYROM)) --> + <item>mi-NZ</item> <!-- Maori (New Zealand) --> + <item>mk-MK</item> <!-- Macedonian (North Macedonia) --> <item>ml-IN</item> <!-- Malayalam (India) --> <item>mn-MN</item> <!-- Mongolian (Mongolia) --> + <item>mni-IN</item> <!-- Manipuri (India) --> + <item>mni-IN-u-nu-latn</item> <!-- Manipuri (India, Western Digits) --> <item>mr-IN</item> <!-- Marathi (India) --> + <item>mr-IN-u-nu-latn</item> <!-- Marathi (India, Western Digits) --> <item>ms-BN</item> <!-- Malay (Brunei) --> + <item>ms-ID</item> <!-- Malay (Indonesia) --> <item>ms-MY</item> <!-- Malay (Malaysia) --> <item>ms-SG</item> <!-- Malay (Singapore) --> <item>mt-MT</item> <!-- Maltese (Malta) --> <item>my-MM</item> <!-- Burmese (Myanmar (Burma)) --> <item>my-MM-u-nu-latn</item> <!-- Burmese (Myanmar (Burma), Western Digits) --> <item>mzn-IR</item> <!-- Mazanderani (Iran) --> + <item>mzn-IR-u-nu-latn</item> <!-- Mazanderani (Iran, Western Digits) --> <item>naq-NA</item> <!-- Nama (Namibia) --> <item>nb-NO</item> <!-- Norwegian Bokmål (Norway) --> <item>nb-SJ</item> <!-- Norwegian Bokmål (Svalbard & Jan Mayen) --> <item>nd-ZW</item> <!-- North Ndebele (Zimbabwe) --> <item>ne-IN</item> <!-- Nepali (India) --> + <item>ne-IN-u-nu-latn</item> <!-- Nepali (India, Western Digits) --> <item>ne-NP</item> <!-- Nepali (Nepal) --> + <item>ne-NP-u-nu-latn</item> <!-- Nepali (Nepal, Western Digits) --> <item>nl-AW</item> <!-- Dutch (Aruba) --> <item>nl-BE</item> <!-- Dutch (Belgium) --> <item>nl-BQ</item> <!-- Dutch (Caribbean Netherlands) --> @@ -427,14 +476,22 @@ <item>os-GE</item> <!-- Ossetic (Georgia) --> <item>os-RU</item> <!-- Ossetic (Russia) --> <item>pa-Arab-PK</item> <!-- Punjabi (Arabic, Pakistan) --> + <item>pa-Arab-PK-u-nu-latn</item> <!-- Punjabi (Arabic, Pakistan, Western Digits) --> <item>pa-Guru-IN</item> <!-- Punjabi (Gurmukhi, India) --> + <item>pcm-NG</item> <!-- Nigerian Pidgin (Nigeria) --> <item>pl-PL</item> <!-- Polish (Poland) --> <item>ps-AF</item> <!-- Pashto (Afghanistan) --> + <item>ps-AF-u-nu-latn</item> <!-- Pashto (Afghanistan, Western Digits) --> + <item>ps-PK</item> <!-- Pashto (Pakistan) --> + <item>ps-PK-u-nu-latn</item> <!-- Pashto (Pakistan, Western Digits) --> <item>pt-AO</item> <!-- Portuguese (Angola) --> <item>pt-BR</item> <!-- Portuguese (Brazil) --> + <item>pt-CH</item> <!-- Portuguese (Switzerland) --> <item>pt-CV</item> <!-- Portuguese (Cape Verde) --> + <item>pt-GQ</item> <!-- Portuguese (Equatorial Guinea) --> <item>pt-GW</item> <!-- Portuguese (Guinea-Bissau) --> - <item>pt-MO</item> <!-- Portuguese (Macau) --> + <item>pt-LU</item> <!-- Portuguese (Luxembourg) --> + <item>pt-MO</item> <!-- Portuguese (Macao) --> <item>pt-MZ</item> <!-- Portuguese (Mozambique) --> <item>pt-PT</item> <!-- Portuguese (Portugal) --> <item>pt-ST</item> <!-- Portuguese (São Tomé & Príncipe) --> @@ -455,9 +512,15 @@ <item>ru-UA</item> <!-- Russian (Ukraine) --> <item>rw-RW</item> <!-- Kinyarwanda (Rwanda) --> <item>rwk-TZ</item> <!-- Rwa (Tanzania) --> + <item>sa-IN</item> <!-- Sanskrit (India) --> <item>sah-RU</item> <!-- Sakha (Russia) --> <item>saq-KE</item> <!-- Samburu (Kenya) --> + <item>sat-IN</item> <!-- Santali (India) --> + <item>sat-IN-u-nu-latn</item> <!-- Santali (India, Western Digits) --> <item>sbp-TZ</item> <!-- Sangu (Tanzania) --> + <item>sd-Arab-PK</item> <!-- Sindhi (Arabic, Pakistan) --> + <item>sd-Arab-PK-u-nu-latn</item> <!-- Sindhi (Arabic, Pakistan, Western Digits) --> + <item>sd-Deva-IN</item> <!-- Sindhi (Devanagari, India) --> <item>se-FI</item> <!-- Northern Sami (Finland) --> <item>se-NO</item> <!-- Northern Sami (Norway) --> <item>se-SE</item> <!-- Northern Sami (Sweden) --> @@ -474,7 +537,7 @@ <item>so-KE</item> <!-- Somali (Kenya) --> <item>so-SO</item> <!-- Somali (Somalia) --> <item>sq-AL</item> <!-- Albanian (Albania) --> - <item>sq-MK</item> <!-- Albanian (Macedonia (FYROM)) --> + <item>sq-MK</item> <!-- Albanian (North Macedonia) --> <item>sq-XK</item> <!-- Albanian (Kosovo) --> <item>sr-Cyrl-BA</item> <!-- Serbian (Cyrillic, Bosnia & Herzegovina) --> <item>sr-Cyrl-ME</item> <!-- Serbian (Cyrillic, Montenegro) --> @@ -484,6 +547,7 @@ <item>sr-Latn-ME</item> <!-- Serbian (Latin, Montenegro) --> <item>sr-Latn-RS</item> <!-- Serbian (Latin, Serbia) --> <item>sr-Latn-XK</item> <!-- Serbian (Latin, Kosovo) --> + <item>su-ID</item> <!-- Sundanese (Indonesia) --> <item>sv-AX</item> <!-- Swedish (Åland Islands) --> <item>sv-FI</item> <!-- Swedish (Finland) --> <item>sv-SE</item> <!-- Swedish (Sweden) --> @@ -498,10 +562,13 @@ <item>te-IN</item> <!-- Telugu (India) --> <item>teo-KE</item> <!-- Teso (Kenya) --> <item>teo-UG</item> <!-- Teso (Uganda) --> + <item>tg-TJ</item> <!-- Tajik (Tajikistan) --> <item>th-TH</item> <!-- Thai (Thailand) --> + <item>tk-TM</item> <!-- Turkmen (Turkmenistan) --> <item>to-TO</item> <!-- Tongan (Tonga) --> <item>tr-CY</item> <!-- Turkish (Cyprus) --> <item>tr-TR</item> <!-- Turkish (Turkey) --> + <item>tt-RU</item> <!-- Tatar (Russia) --> <item>twq-NE</item> <!-- Tasawaq (Niger) --> <item>tzm-MA</item> <!-- Central Atlas Tamazight (Morocco) --> <item>ug-CN</item> <!-- Uyghur (China) --> @@ -511,11 +578,13 @@ <item>ur-PK</item> <!-- Urdu (Pakistan) --> <item>ur-PK-u-nu-arabext</item> <!-- Urdu (Pakistan, Extended Arabic-Indic Digits) --> <item>uz-Arab-AF</item> <!-- Uzbek (Arabic, Afghanistan) --> + <item>uz-Arab-AF-u-nu-latn</item> <!-- Uzbek (Arabic, Afghanistan, Western Digits) --> <item>uz-Cyrl-UZ</item> <!-- Uzbek (Cyrillic, Uzbekistan) --> <item>uz-Latn-UZ</item> <!-- Uzbek (Latin, Uzbekistan) --> <item>vi-VN</item> <!-- Vietnamese (Vietnam) --> <item>vun-TZ</item> <!-- Vunjo (Tanzania) --> <item>wae-CH</item> <!-- Walser (Switzerland) --> + <item>wo-SN</item> <!-- Wolof (Senegal) --> <item>xog-UG</item> <!-- Soga (Uganda) --> <item>yav-CM</item> <!-- Yangben (Cameroon) --> <item>yo-BJ</item> <!-- Yoruba (Benin) --> @@ -525,10 +594,10 @@ <item>zgh-MA</item> <!-- Standard Moroccan Tamazight (Morocco) --> <item>zh-Hans-CN</item> <!-- Chinese (Simplified, China) --> <item>zh-Hans-HK</item> <!-- Chinese (Simplified, Hong Kong) --> - <item>zh-Hans-MO</item> <!-- Chinese (Simplified, Macau) --> + <item>zh-Hans-MO</item> <!-- Chinese (Simplified, Macao) --> <item>zh-Hans-SG</item> <!-- Chinese (Simplified, Singapore) --> <item>zh-Hant-HK</item> <!-- Chinese (Traditional, Hong Kong) --> - <item>zh-Hant-MO</item> <!-- Chinese (Traditional, Macau) --> + <item>zh-Hant-MO</item> <!-- Chinese (Traditional, Macao) --> <item>zh-Hant-TW</item> <!-- Chinese (Traditional, Taiwan) --> <item>zu-ZA</item> <!-- Zulu (South Africa) --> </string-array> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index c71600074217..0e9526ab4e6c 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3097,7 +3097,7 @@ <public name="playHomeTransitionSound" /> <public name="lStar" /> <!-- @hide @SystemApi --> - <public name="throttleDurationMillis" /> + <public name="durationBetweenRequestsMillis" /> <public name="showInInputMethodPicker" /> <public name="effectColor" /> </staging-public-group> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index fd33ccdfb8c5..270b98ebebe3 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -6006,4 +6006,8 @@ ul.</string> <string name="view_and_control_notification_title">Check access settings</string> <!-- Notification content to prompt the user that some accessibility service has view and control access. [CHAR LIMIT=none] --> <string name="view_and_control_notification_content"><xliff:g id="service_name" example="TalkBack">%s</xliff:g> can view and control your screen. Tap to review.</string> + <!-- Accessibility message announced when the view text displayed on the screen that has been translated to a different language by the system. [CHAR LIMIT=NONE] --> + <string name="ui_translation_accessibility_translated_text"><xliff:g id="message" example="Hello">%1$s</xliff:g> Translated.</string> + <!-- Accessibility message announced to notify the user when the system has finished translating the content displayed on the screen to a different language after the user requested translation. [CHAR LIMIT=NONE] --> + <string name="ui_translation_accessibility_translation_finished">Message translated from <xliff:g id="from_language" example="English">%1$s</xliff:g> to <xliff:g id="to_language" example="French">%2$s</xliff:g>.</string> </resources> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index fbf67e0d84ac..bac9cf23b176 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -964,7 +964,7 @@ please see styles_device_defaults.xml. </style> <style name="TextAppearance.Toast"> - <item name="fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="fontFamily">@*android:string/config_bodyFontFamily</item> <item name="textSize">14sp</item> <item name="textColor">?android:attr/textColorPrimary</item> </style> diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml index 439ae48ebc54..ad0d0e07be1e 100644 --- a/core/res/res/values/styles_device_defaults.xml +++ b/core/res/res/values/styles_device_defaults.xml @@ -302,10 +302,6 @@ easier. <style name="TextAppearance.DeviceDefault.Notification.Time" parent="TextAppearance.Material.Notification.Time"> <item name="fontFamily">@string/config_bodyFontFamily</item> </style> - <style name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" - parent="TextAppearance.Material.Notification.Conversation.AppName"> - <item name="fontFamily">@string/config_headlineFontFamilyMedium</item> - </style> <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Material.Widget"> <item name="fontFamily">@string/config_bodyFontFamily</item> </style> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 3c4a5d4aab73..eec6ae3fb521 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -497,10 +497,6 @@ please see styles_device_defaults.xml. <!-- 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> - </style> - <style name="TextAppearance.Material.ListItem" parent="TextAppearance.Material.Subhead" /> <style name="TextAppearance.Material.ListItemSecondary" parent="TextAppearance.Material.Body1" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 78a794a35bba..b9f1e203552a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3083,6 +3083,7 @@ <java-symbol type="string" name="negative_duration" /> <java-symbol type="dimen" name="notification_messaging_spacing" /> + <java-symbol type="dimen" name="notification_messaging_spacing_conversation_group" /> <java-symbol type="dimen" name="notification_text_margin_top" /> <java-symbol type="dimen" name="notification_inbox_item_top_padding" /> @@ -3403,6 +3404,7 @@ <java-symbol type="drawable" name="ic_accessibility_color_inversion" /> <java-symbol type="drawable" name="ic_accessibility_color_correction" /> <java-symbol type="drawable" name="ic_accessibility_magnification" /> + <java-symbol type="drawable" name="ic_accessibility_reduce_bright_colors" /> <java-symbol type="string" name="reduce_bright_colors_feature_name" /> @@ -3800,6 +3802,7 @@ <!-- For Foldables --> <java-symbol type="array" name="config_foldedDeviceStates" /> <java-symbol type="string" name="config_foldedArea" /> + <java-symbol type="bool" name="config_supportsConcurrentInternalDisplays" /> <java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" /> <java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" /> @@ -4089,7 +4092,6 @@ <java-symbol type="dimen" name="button_inset_horizontal_material" /> <java-symbol type="layout" name="conversation_face_pile_layout" /> <java-symbol type="string" name="unread_convo_overflow" /> - <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" /> <java-symbol type="drawable" name="conversation_badge_background" /> <java-symbol type="drawable" name="conversation_badge_ring" /> <java-symbol type="color" name="conversation_important_highlight" /> @@ -4355,6 +4357,11 @@ <java-symbol type="drawable" name="ic_accessibility_24dp" /> <java-symbol type="string" name="view_and_control_notification_title" /> <java-symbol type="string" name="view_and_control_notification_content" /> + <java-symbol type="array" name="config_accessibility_allowed_install_source" /> + + <!-- Translation --> + <java-symbol type="string" name="ui_translation_accessibility_translated_text" /> + <java-symbol type="string" name="ui_translation_accessibility_translation_finished" /> <java-symbol type="layout" name="notification_expand_button"/> diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index d5733e34a8ef..2650d9f69dd7 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -40,7 +40,7 @@ <shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" /> <!-- Argentina: 5 digits, known short codes listed --> - <shortcode country="ar" pattern="\\d{5}" free="11711|28291" /> + <shortcode country="ar" pattern="\\d{5}" free="11711|28291|44077" /> <!-- Armenia: 3-4 digits, emergency numbers 10[123] --> <shortcode country="am" pattern="\\d{3,4}" premium="11[2456]1|3024" free="10[123]" /> @@ -76,14 +76,14 @@ <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" free="98765|30075|30047" /> <!-- Chile: 4-5 digits (not confirmed), known premium codes listed --> - <shortcode country="cl" pattern="\\d{4,5}" free="9963|9240" /> + <shortcode country="cl" pattern="\\d{4,5}" free="9963|9240|1038" /> <!-- China: premium shortcodes start with "1066", free shortcodes start with "1065": http://clients.txtnation.com/entries/197192-china-premium-sms-short-code-requirements --> <shortcode country="cn" premium="1066.*" free="1065.*" /> <!-- Colombia: 1-6 digits (not confirmed) --> - <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960" /> + <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960|899948|87739" /> <!-- Cyprus: 4-6 digits (not confirmed), known premium codes listed, plus EU --> <shortcode country="cy" pattern="\\d{4,6}" premium="7510" free="116\\d{3}" /> @@ -156,7 +156,7 @@ <shortcode country="jp" pattern="\\d{1,5}" free="8083" /> <!-- Kenya: 5 digits, known premium codes listed --> - <shortcode country="ke" pattern="\\d{5}" free="21725" /> + <shortcode country="ke" pattern="\\d{5}" free="21725|21562|40520" /> <!-- Kyrgyzstan: 4 digits, known premium codes listed --> <shortcode country="kg" pattern="\\d{4}" premium="415[2367]|444[69]" /> @@ -187,13 +187,13 @@ <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963" /> <!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf --> - <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288" /> + <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" /> <!-- The Netherlands, 4 digits, known premium codes listed, plus EU --> <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" /> <!-- Nigeria --> - <shortcode country="ng" pattern="\\d{1,5}" free="2441" /> + <shortcode country="ng" pattern="\\d{1,5}" free="2441|55019" /> <!-- Norway: 4-5 digits (not confirmed), known premium codes listed --> <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" /> @@ -202,7 +202,7 @@ <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="1737|176|2141|3067|3068|3110|4006|4053|4061|4062|4202|4300|4334|4412|4575|5626|8006|8681" /> <!-- Peru: 4-5 digits (not confirmed), known premium codes listed --> - <shortcode country="pe" pattern="\\d{4,5}" free="9963" /> + <shortcode country="pe" pattern="\\d{4,5}" free="9963|40777" /> <!-- Philippines --> <shortcode country="ph" pattern="\\d{1,5}" free="2147|5495|5496" /> @@ -224,7 +224,7 @@ <shortcode country="re" pattern="\\d{1,5}" free="38600,36300,36303,959" /> <!-- Romania: 4 digits, plus EU: http://www.simplus.ro/en/resources/glossary-of-terms/ --> - <shortcode country="ro" pattern="\\d{4}" premium="12(?:63|66|88)|13(?:14|80)" free="116\\d{3}|3654|8360" /> + <shortcode country="ro" pattern="\\d{4}" premium="12(?:63|66|88)|13(?:14|80)" free="116\\d{3}|3654|8360|3838" /> <!-- Russia: 4 digits, known premium codes listed: http://smscoin.net/info/pricing-russia/ --> <shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)|8424" free="6954|8501" standard="2037|2044"/> @@ -252,7 +252,7 @@ <shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" /> <!-- Turkey --> - <shortcode country="tr" pattern="\\d{1,5}" free="7529|5528|6493" /> + <shortcode country="tr" pattern="\\d{1,5}" free="7529|5528|6493|3193" /> <!-- Ukraine: 4 digits, known premium codes listed --> <shortcode country="ua" pattern="\\d{4}" premium="444[3-9]|70[579]4|7540" /> @@ -268,6 +268,6 @@ <shortcode country="yt" pattern="\\d{1,5}" free="38600,36300,36303,959" /> <!-- South Africa --> - <shortcode country="za" pattern="\d{1,5}" free="44136" /> + <shortcode country="za" pattern="\d{1,5}" free="44136|30791|36056" /> </shortcodes> diff --git a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java index 0f3bb1db6ed9..81ec3f37c465 100644 --- a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java +++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java @@ -58,11 +58,8 @@ public class PowerMetrics { for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) { - totalPowerPerComponentMah[component] += uidBatteryConsumer.getConsumedPower( - component); - } - - for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) { + totalPowerPerComponentMah[component] += + uidBatteryConsumer.getConsumedPower(component); totalDurationPerComponentMs[component] += uidBatteryConsumer.getUsageDurationMillis(component); } @@ -76,18 +73,15 @@ public class PowerMetrics { addMetric(getPowerMetricName(component), MetricKind.POWER, selectedBatteryConsumer.getConsumedPower(component), totalPowerPerComponentMah[component]); - } - - for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) { - addMetric(getTimeMetricName(component), MetricKind.DURATION, + addMetric(getDurationMetricName(component), MetricKind.DURATION, selectedBatteryConsumer.getUsageDurationMillis(component), totalDurationPerComponentMs[component]); } } - static String getTimeMetricName(int componentId) { - return "TIME_" + DebugUtils.constantToString(BatteryConsumer.class, - "TIME_COMPONENT_", componentId); + static String getDurationMetricName(int componentId) { + return "DURATION_" + DebugUtils.constantToString(BatteryConsumer.class, + "POWER_COMPONENT_", componentId); } static String getPowerMetricName(int componentId) { diff --git a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java index 5b5da603b199..6fc10dd5264a 100644 --- a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java +++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java @@ -306,8 +306,8 @@ public class PowerMetricsCollector implements TestRule { return null; } - public PowerMetrics.Metric getTimeMetric(@BatteryConsumer.TimeComponent int component) { - final String name = PowerMetrics.getTimeMetricName(component); + public PowerMetrics.Metric getTimeMetric(@BatteryConsumer.PowerComponent int component) { + final String name = PowerMetrics.getDurationMetricName(component); for (PowerMetrics.Metric metric : mPowerMetricsDelta) { if (metric.metricName.equals(name)) { return metric; diff --git a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml index 52a77a7862a1..1b1f64afcbae 100644 --- a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml +++ b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml @@ -27,6 +27,7 @@ android:label="Battery Stats Viewer"> <activity android:name=".BatteryConsumerPickerActivity" android:label="Battery Stats" + android:icon="@mipmap/ic_launcher" android:launchMode="singleTop" android:exported="true"> <intent-filter> @@ -36,7 +37,6 @@ </activity> <activity android:name=".BatteryStatsViewerActivity" - android:icon="@mipmap/ic_launcher" android:label="Battery Stats" android:parentActivityName=".BatteryConsumerPickerActivity"/> </application> diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java index f7d7098b1726..a15a8d8b3f47 100644 --- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java +++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java @@ -68,7 +68,7 @@ public class BatteryConsumerData { double[] totalPowerByComponentMah = new double[BatteryConsumer.POWER_COMPONENT_COUNT]; double[] totalModeledPowerByComponentMah = new double[BatteryConsumer.POWER_COMPONENT_COUNT]; - long[] totalDurationByComponentMs = new long[BatteryConsumer.TIME_COMPONENT_COUNT]; + long[] totalDurationByComponentMs = new long[BatteryConsumer.POWER_COMPONENT_COUNT]; final int customComponentCount = requestedBatteryConsumer.getCustomPowerComponentCount(); double[] totalCustomPowerByComponentMah = new double[customComponentCount]; @@ -108,7 +108,7 @@ public class BatteryConsumerData { mBatteryConsumerInfo.isSystemBatteryConsumer); } - for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) { + for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) { final String metricTitle = getTimeMetricTitle(component); addEntry(metricTitle, EntryType.DURATION, requestedBatteryConsumer.getUsageDurationMillis(component), @@ -141,7 +141,7 @@ public class BatteryConsumerData { static String getTimeMetricTitle(int componentId) { final String componentName = DebugUtils.constantToString(BatteryConsumer.class, - "TIME_COMPONENT_", componentId); + "POWER_COMPONENT_", componentId); return componentName.charAt(0) + componentName.substring(1).toLowerCase().replace('_', ' ') + " time"; } @@ -159,7 +159,7 @@ public class BatteryConsumerData { private void computeTotalDuration(BatteryUsageStats batteryUsageStats, long[] durationByComponentMs) { for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) { - for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; + for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) { durationByComponentMs[component] += consumer.getUsageDurationMillis(component); } diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java index b2b9ab31282c..c9a18dafe11d 100644 --- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java +++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java @@ -30,6 +30,7 @@ import static android.app.admin.PasswordMetrics.validatePasswordMetrics; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -284,33 +285,42 @@ public class PasswordMetricsTest { PasswordMetrics none = new PasswordMetrics(CREDENTIAL_TYPE_NONE); PasswordMetrics pattern = new PasswordMetrics(CREDENTIAL_TYPE_PATTERN); PasswordMetrics password = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD); + PasswordMetrics pin = new PasswordMetrics(CREDENTIAL_TYPE_PIN); // To pass minimal length check. password.length = 4; + pin.length = 4; // No errors expected, credential is of stronger or equal type. assertValidationErrors( - validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, false, none)); + validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, none)); assertValidationErrors( - validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, false, pattern)); + validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, pattern)); assertValidationErrors( - validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, false, password)); + validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, password)); assertValidationErrors( - validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, false, pattern)); + validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, pin)); assertValidationErrors( - validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, false, password)); + validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, pattern)); assertValidationErrors( - validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, false, password)); + validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, password)); + assertValidationErrors( + validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, password)); + assertValidationErrors( + validatePasswordMetrics(pin, PASSWORD_COMPLEXITY_NONE, pin)); // Now actual credential type is weaker than required: assertValidationErrors( - validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, false, none), + validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, none), + PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0); + assertValidationErrors( + validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, none), PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0); assertValidationErrors( - validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, false, none), + validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, pattern), PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0); assertValidationErrors( - validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, false, pattern), + validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, pin), PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0); } diff --git a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java index 36da927116b7..3e2c4e98e21a 100644 --- a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java +++ b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java @@ -234,6 +234,7 @@ public class PeopleSpaceTileTest { .setIsImportantConversation(true) .setStatuses(statusList).setNotificationKey("key") .setNotificationContent("content") + .setNotificationSender("sender") .setNotificationDataUri(Uri.parse("data")) .setMessagesCount(2) .setIntent(new Intent()) @@ -256,6 +257,7 @@ public class PeopleSpaceTileTest { assertThat(readTile.getStatuses()).isEqualTo(tile.getStatuses()); assertThat(readTile.getNotificationKey()).isEqualTo(tile.getNotificationKey()); assertThat(readTile.getNotificationContent()).isEqualTo(tile.getNotificationContent()); + assertThat(readTile.getNotificationSender()).isEqualTo(tile.getNotificationSender()); assertThat(readTile.getNotificationDataUri()).isEqualTo(tile.getNotificationDataUri()); assertThat(readTile.getMessagesCount()).isEqualTo(tile.getMessagesCount()); assertThat(readTile.getIntent().toString()).isEqualTo(tile.getIntent().toString()); @@ -282,6 +284,16 @@ public class PeopleSpaceTileTest { } @Test + public void testNotificationSender() { + PeopleSpaceTile tile = new PeopleSpaceTile + .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps) + .setNotificationSender("test") + .build(); + + assertThat(tile.getNotificationSender()).isEqualTo("test"); + } + + @Test public void testNotificationDataUri() { PeopleSpaceTile tile = new PeopleSpaceTile.Builder(new ShortcutInfo.Builder(mContext, "123").build(), diff --git a/core/tests/coretests/src/android/graphics/FontListParserTest.java b/core/tests/coretests/src/android/graphics/FontListParserTest.java index b2df98dc6374..22f6ec0b24b1 100644 --- a/core/tests/coretests/src/android/graphics/FontListParserTest.java +++ b/core/tests/coretests/src/android/graphics/FontListParserTest.java @@ -325,6 +325,6 @@ public final class FontListParserTest { XmlPullParser parser = Xml.newPullParser(); parser.setInput(buffer, "UTF-8"); parser.nextTag(); - return FontListParser.readFamily(parser, "", null); + return FontListParser.readFamily(parser, "", null, true); } } diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java index 412b36713fa2..8b39beb8cf54 100644 --- a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java +++ b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java @@ -33,6 +33,7 @@ import static org.mockito.Mockito.when; import android.hardware.lights.Light; import android.hardware.lights.LightState; import android.hardware.lights.LightsManager; +import android.hardware.lights.LightsRequest; import android.os.IBinder; import android.platform.test.annotations.Presubmit; import android.util.ArrayMap; @@ -224,4 +225,25 @@ public class InputDeviceLightsManagerTest { session.close(); verify(mIInputManagerMock).closeLightSession(eq(DEVICE_ID), eq(token)); } + + @Test + public void testLightsRequest() throws Exception { + Light light = new Light(1 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_PLAYER_ID); + LightState state = new LightState(0xf1); + LightsRequest request = new Builder().addLight(light, state).build(); + + // Covers the LightsRequest.getLights + assertThat(request.getLights().size()).isEqualTo(1); + assertThat(request.getLights().get(0)).isEqualTo(1); + + // Covers the LightsRequest.getLightStates + assertThat(request.getLightStates().size()).isEqualTo(1); + assertThat(request.getLightStates().get(0)).isEqualTo(state); + + // Covers the LightsRequest.getLightsAndStates + assertThat(request.getLightsAndStates().size()).isEqualTo(1); + assertThat(request.getLightsAndStates().containsKey(1)).isTrue(); + assertThat(request.getLightsAndStates().get(1)).isEqualTo(state); + } + } diff --git a/core/tests/coretests/src/android/os/VibratorInfoTest.java b/core/tests/coretests/src/android/os/VibratorInfoTest.java index 9880f8c52971..8c7d10c7a5ef 100644 --- a/core/tests/coretests/src/android/os/VibratorInfoTest.java +++ b/core/tests/coretests/src/android/os/VibratorInfoTest.java @@ -108,6 +108,8 @@ public class VibratorInfoTest { .build(); assertEquals(20, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK)); assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_TICK)); + assertEquals(0, new VibratorInfo.Builder(TEST_VIBRATOR_ID).build() + .getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_TICK)); } @Test diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java index c63ec45ed5a9..236c3daac272 100644 --- a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java @@ -65,7 +65,7 @@ public class AmbientDisplayPowerCalculatorTest { SystemBatteryConsumer consumer = mStatsRule.getSystemBatteryConsumer( SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) .isEqualTo(90 * MINUTE_IN_MS); // 100,000,00 uC / 1000 (micro-/milli-) / 360 (seconds/hour) = 27.777778 mAh assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) @@ -91,7 +91,7 @@ public class AmbientDisplayPowerCalculatorTest { SystemBatteryConsumer consumer = mStatsRule.getSystemBatteryConsumer( SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) .isEqualTo(90 * MINUTE_IN_MS); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) .isWithin(PRECISION).of(15.0); diff --git a/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java index ed4638c1e7e0..c694d67cd97b 100644 --- a/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java @@ -52,7 +52,7 @@ public class AudioPowerCalculatorTest { mStatsRule.apply(calculator); UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)) .isEqualTo(1000); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO)) .isWithin(PRECISION).of(0.1); diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java index e0739be1b295..41fe372d5d9c 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java @@ -171,7 +171,7 @@ public class BatteryUsageStatsRule implements TestRule { final boolean includePowerModels = (query.getFlags() & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0; BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder( - customPowerComponentNames, 0, includePowerModels); + customPowerComponentNames, includePowerModels); SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats(); for (int i = 0; i < uidStats.size(); i++) { builder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i)); diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java index b25359970c5a..55302bcf3b8d 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java @@ -67,7 +67,7 @@ public class BatteryUsageStatsTest { final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000); final BatteryUsageStats.Builder builder = - new BatteryUsageStats.Builder(new String[]{"FOO"}, 1) + new BatteryUsageStats.Builder(new String[]{"FOO"}) .setDischargePercentage(20) .setDischargedPowerRange(1000, 2000) .setStatsStartTimestamp(1000); @@ -83,11 +83,9 @@ public class BatteryUsageStatsTest { .setConsumedPowerForCustomComponent( BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500) .setUsageDurationMillis( - BatteryConsumer.TIME_COMPONENT_CPU, 600) - .setUsageDurationMillis( - BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, 700) + BatteryConsumer.POWER_COMPONENT_CPU, 600) .setUsageDurationForCustomComponentMillis( - BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 800); + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 800); builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_CAMERA) .setConsumedPower( @@ -95,9 +93,9 @@ public class BatteryUsageStatsTest { .setConsumedPowerForCustomComponent( BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200) .setUsageDurationMillis( - BatteryConsumer.TIME_COMPONENT_CPU, 10300) + BatteryConsumer.POWER_COMPONENT_CPU, 10300) .setUsageDurationForCustomComponentMillis( - BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400) + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10400) .setPowerConsumedByApps(20000); return builder.build(); @@ -129,11 +127,9 @@ public class BatteryUsageStatsTest { assertThat(uidBatteryConsumer.getConsumedPowerForCustomComponent( BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(500); assertThat(uidBatteryConsumer.getUsageDurationMillis( - BatteryConsumer.TIME_COMPONENT_CPU)).isEqualTo(600); - assertThat(uidBatteryConsumer.getUsageDurationMillis( - BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND)).isEqualTo(700); + BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(600); assertThat(uidBatteryConsumer.getUsageDurationForCustomComponentMillis( - BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(800); + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(800); assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(1200); assertThat(uidBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1); assertThat(uidBatteryConsumer.getCustomPowerComponentName( @@ -152,9 +148,9 @@ public class BatteryUsageStatsTest { assertThat(systemBatteryConsumer.getConsumedPowerForCustomComponent( BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(10200); assertThat(systemBatteryConsumer.getUsageDurationMillis( - BatteryConsumer.TIME_COMPONENT_CPU)).isEqualTo(10300); + BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10300); assertThat(systemBatteryConsumer.getUsageDurationForCustomComponentMillis( - BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(10400); + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(10400); assertThat(systemBatteryConsumer.getConsumedPower()).isEqualTo(20300); assertThat(systemBatteryConsumer.getPowerConsumedByApps()).isEqualTo(20000); assertThat(systemBatteryConsumer.getUsageDurationMillis()) diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java index 78901683eca1..e2e672ea6f68 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java @@ -938,17 +938,9 @@ public class BinderCallsStatsTest { } @Test - public void testLatencyCollectionDisabledByDefault() { + public void testLatencyCollectionEnabledByDefault() { TestBinderCallsStats bcs = new TestBinderCallsStats(); - assertEquals(false, bcs.getCollectLatencyData()); - - Binder binder = new Binder(); - CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); - bcs.time += 10; - bcs.elapsedTime += 20; - bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); - - assertEquals(0, bcs.getLatencyObserver().getLatencyHistograms().size()); + assertEquals(true, bcs.getCollectLatencyData()); } private static class TestHandler extends Handler { @@ -992,8 +984,9 @@ public class BinderCallsStatsTest { return mHandler; } - public BinderLatencyObserver getLatencyObserver() { - return new BinderLatencyObserverTest.TestBinderLatencyObserver(); + @Override + public BinderLatencyObserver getLatencyObserver(int processSource) { + return new BinderLatencyObserverTest.TestBinderLatencyObserver(processSource); } }); setSamplingInterval(1); diff --git a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java index bf87683593e7..4157f5e72871 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java @@ -245,18 +245,24 @@ public class BinderLatencyObserverTest { private ArrayList<String> mWrittenAtoms; TestBinderLatencyObserver() { - // Make random generator not random. - super(new Injector() { - public Random getRandomGenerator() { - return new Random() { - int mCallCount = 0; + this(SYSTEM_SERVER); + } - public int nextInt() { - return mCallCount++; + TestBinderLatencyObserver(int processSource) { + // Make random generator not random. + super( + new Injector() { + public Random getRandomGenerator() { + return new Random() { + int mCallCount = 0; + + public int nextInt() { + return mCallCount++; + } + }; } - }; - } - }); + }, + processSource); setSamplingInterval(1); mWrittenAtoms = new ArrayList<>(); } 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 71cdb5fe17f0..8723195ab6fe 100644 --- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java @@ -147,7 +147,7 @@ public class BluetoothPowerCalculatorTest { .isEqualTo(powerModel); long usageDurationMillis = batteryConsumer.getUsageDurationMillis( - BatteryConsumer.TIME_COMPONENT_BLUETOOTH); + BatteryConsumer.POWER_COMPONENT_BLUETOOTH); assertThat(usageDurationMillis).isEqualTo(durationMs); } 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 a181bc8ba4da..1fc3a2118385 100644 --- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java @@ -354,6 +354,7 @@ public class BstatsCpuTimesValidationTest { batteryOffScreenOn(); } + @SkipPresubmit("b/185960974 flaky") @Test public void testCpuFreqTimes_stateTopSleeping() throws Exception { if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) { diff --git a/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java index a21dd58b0757..61eb173837e8 100644 --- a/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java @@ -52,7 +52,7 @@ public class CameraPowerCalculatorTest { mStatsRule.apply(calculator); UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CAMERA)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) .isEqualTo(1000); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) .isWithin(PRECISION).of(0.1); 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 63af21dcdd93..1a99fb0fd40f 100644 --- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java @@ -144,7 +144,7 @@ public class CpuPowerCalculatorTest { mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1); - assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU)) + assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU)) .isEqualTo(3333); assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU)) .isWithin(PRECISION).of(1.092233); @@ -153,7 +153,7 @@ public class CpuPowerCalculatorTest { assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar"); UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2); - assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU)) + assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU)) .isEqualTo(7777); assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU)) .isWithin(PRECISION).of(2.672322); @@ -208,7 +208,7 @@ public class CpuPowerCalculatorTest { mStatsRule.apply(calculator); UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1); - assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU)) + assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU)) .isEqualTo(3333); assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU)) .isWithin(PRECISION).of(3.18877); @@ -217,7 +217,7 @@ public class CpuPowerCalculatorTest { assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar"); UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2); - assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU)) + assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CPU)) .isEqualTo(7777); assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU)) .isWithin(PRECISION).of(7.44072); diff --git a/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java index b7bbedd9cdb7..98d5aacd7f8e 100644 --- a/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java @@ -52,7 +52,7 @@ public class FlashlightPowerCalculatorTest { mStatsRule.apply(calculator); UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_FLASHLIGHT)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) .isEqualTo(1000); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) .isWithin(PRECISION).of(0.1); diff --git a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java index aa066c36cd4b..7ea799ff5173 100644 --- a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java @@ -56,7 +56,7 @@ public class GnssPowerCalculatorTest { mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_GNSS)) .isEqualTo(1000); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS)) .isWithin(PRECISION).of(0.1); @@ -83,7 +83,7 @@ public class GnssPowerCalculatorTest { mStatsRule.apply(calculator); UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_GNSS)) .isEqualTo(1000); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS)) .isWithin(PRECISION).of(2.77777); @@ -91,7 +91,7 @@ public class GnssPowerCalculatorTest { .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); UidBatteryConsumer consumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2); - assertThat(consumer2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS)) + assertThat(consumer2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_GNSS)) .isEqualTo(2000); assertThat(consumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS)) .isWithin(PRECISION).of(5.55555); diff --git a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java index a9800b7e6b75..2331eebf6dd1 100644 --- a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java @@ -48,7 +48,7 @@ public class IdlePowerCalculatorTest { SystemBatteryConsumer consumer = mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_IDLE); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_IDLE)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_IDLE)) .isEqualTo(3000); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE)) .isWithin(PRECISION).of(0.7); diff --git a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java index 71dbcdbf7f46..94e760a4e2e2 100644 --- a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java @@ -55,7 +55,7 @@ public class MemoryPowerCalculatorTest { SystemBatteryConsumer consumer = mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_MEMORY); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MEMORY)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MEMORY)) .isEqualTo(3000); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY)) .isWithin(PRECISION).of(0.7); diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java index 7d829e44d9ec..93c71068457e 100644 --- a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java @@ -84,7 +84,7 @@ public class ScreenPowerCalculatorTest { SystemBatteryConsumer consumer = mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) .isEqualTo(80 * MINUTE_IN_MS); // 600000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s) = 166.66666 mAh @@ -98,7 +98,7 @@ public class ScreenPowerCalculatorTest { .isWithin(PRECISION).of(166.66666); UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1); - assertThat(uid1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN)) + assertThat(uid1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) .isEqualTo(20 * MINUTE_IN_MS); // Uid1 took all of the foreground time during the first Display update. @@ -110,7 +110,7 @@ public class ScreenPowerCalculatorTest { .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2); - assertThat(uid2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN)) + assertThat(uid2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) .isEqualTo(60 * MINUTE_IN_MS); // Uid2 ran for 40 minutes out of the total 45 min of foreground time during the second @@ -153,7 +153,7 @@ public class ScreenPowerCalculatorTest { SystemBatteryConsumer consumer = mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) .isEqualTo(80 * MINUTE_IN_MS); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) .isWithin(PRECISION).of(92.0); @@ -165,7 +165,7 @@ public class ScreenPowerCalculatorTest { .isWithin(PRECISION).of(92.0); UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1); - assertThat(uid1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN)) + assertThat(uid1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) .isEqualTo(20 * MINUTE_IN_MS); // Uid1 took 20 out of the total of 80 min of foreground activity @@ -176,7 +176,7 @@ public class ScreenPowerCalculatorTest { .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2); - assertThat(uid2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN)) + assertThat(uid2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) .isEqualTo(60 * MINUTE_IN_MS); // Uid2 took 60 out of the total of 80 min of foreground activity diff --git a/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java index b50435bd2928..74235b28d43b 100644 --- a/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java @@ -70,7 +70,7 @@ public class SensorPowerCalculatorTest { mStatsRule.apply(calculator); UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SENSORS)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SENSORS)) .isEqualTo(3000); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS)) .isWithin(PRECISION).of(0.5); diff --git a/core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java index 6fa1d3bae0f7..aae69d7b5bc9 100644 --- a/core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java @@ -58,16 +58,16 @@ public class UserPowerCalculatorTest { assertThat(mStatsRule.getUserBatteryConsumer(USER1)).isNull(); assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1)) - .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(3000); + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(3000); assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1)) - .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(7000); + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(7000); assertThat(mStatsRule.getUserBatteryConsumer(USER2)).isNull(); assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID2)) - .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(5555); + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(5555); assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID2)) - .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(9999); + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(9999); } @Test @@ -82,19 +82,19 @@ public class UserPowerCalculatorTest { assertThat(mStatsRule.getUserBatteryConsumer(USER1)).isNull(); assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1)) - .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(3000); + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(3000); assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1)) - .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(7000); + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(7000); assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID2))).isNull(); assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID3)) - .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(7070); + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)).isEqualTo(7070); assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID3)) - .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(11110); + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)).isEqualTo(11110); UserBatteryConsumer user2 = mStatsRule.getUserBatteryConsumer(USER2); - assertThat(user2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)) + assertThat(user2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO)) .isEqualTo(15308); - assertThat(user2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)) + assertThat(user2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)) .isEqualTo(24196); assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID1))).isNull(); @@ -130,7 +130,7 @@ public class UserPowerCalculatorTest { protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { long durationMs = u.getAudioTurnedOnTimer().getTotalTimeLocked(rawRealtimeUs, 0); - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO, durationMs / 1000); + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO, durationMs / 1000); } } @@ -139,7 +139,7 @@ public class UserPowerCalculatorTest { protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { long durationMs = u.getVideoTurnedOnTimer().getTotalTimeLocked(rawRealtimeUs, 0); - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO, durationMs / 1000); + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO, durationMs / 1000); } } } diff --git a/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java index 39eac49400ec..fa0dbc76d5c6 100644 --- a/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java @@ -52,7 +52,7 @@ public class VideoPowerCalculatorTest { mStatsRule.apply(calculator); UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO)) .isEqualTo(1000); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO)) .isWithin(PRECISION).of(0.1); diff --git a/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java index 4f71b438c6fa..9d3ed55a0729 100644 --- a/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java @@ -62,13 +62,13 @@ public class WakelockPowerCalculatorTest { mStatsRule.apply(calculator); UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK)) + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK)) .isEqualTo(1000); assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK)) .isWithin(PRECISION).of(0.1); UidBatteryConsumer osConsumer = mStatsRule.getUidBatteryConsumer(Process.ROOT_UID); - assertThat(osConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK)) + assertThat(osConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK)) .isEqualTo(5000); assertThat(osConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK)) .isWithin(PRECISION).of(0.5); diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java index 9349bce2c383..4a7cf1e21abe 100644 --- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java @@ -87,7 +87,7 @@ public class WifiPowerCalculatorTest { mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI)) + assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) .isEqualTo(1423); assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) .isWithin(PRECISION).of(0.2214666); @@ -96,7 +96,7 @@ public class WifiPowerCalculatorTest { SystemBatteryConsumer systemConsumer = mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI); - assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI)) + assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) .isEqualTo(5577); assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) .isWithin(PRECISION).of(1.11153); @@ -117,7 +117,7 @@ public class WifiPowerCalculatorTest { mStatsRule.apply(calculator); UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI)) + assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) .isEqualTo(1423); /* Same ratio as in testPowerControllerBasedModel_nonMeasured but scaled by 1_000_000uC. */ assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) @@ -127,7 +127,7 @@ public class WifiPowerCalculatorTest { SystemBatteryConsumer systemConsumer = mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI); - assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI)) + assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) .isEqualTo(5577); /* Same ratio as in testPowerControllerBasedModel_nonMeasured but scaled by 1_000_000uC. */ assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) @@ -162,7 +162,7 @@ public class WifiPowerCalculatorTest { mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI)) + assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) .isEqualTo(1000); assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) .isWithin(PRECISION).of(0.8231573); @@ -171,7 +171,7 @@ public class WifiPowerCalculatorTest { SystemBatteryConsumer systemConsumer = mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI); - assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI)) + assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) .isEqualTo(2222); assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) .isWithin(PRECISION).of(2.575000); @@ -193,7 +193,7 @@ public class WifiPowerCalculatorTest { mStatsRule.apply(calculator); UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI)) + assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) .isEqualTo(1000); /* Same ratio as in testTimerBasedModel_nonMeasured but scaled by 1_000_000uC. */ assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) @@ -203,7 +203,7 @@ public class WifiPowerCalculatorTest { SystemBatteryConsumer systemConsumer = mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI); - assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI)) + assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI)) .isEqualTo(2222); /* Same ratio as in testTimerBasedModel_nonMeasured but scaled by 1_000_000uC. */ assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI)) diff --git a/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java b/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java index 43f9b6feea45..48f4288d401e 100644 --- a/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java +++ b/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java @@ -19,6 +19,7 @@ package android.nfc; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -62,7 +63,36 @@ public class NfcControllerAlwaysOnListenerTest { } @Test + public void testRegister_RegisterUnregisterWhenNotSupported() throws RemoteException { + // isControllerAlwaysOnSupported() returns false, not supported. + doReturn(false).when(mNfcAdapter).isControllerAlwaysOnSupported(); + NfcControllerAlwaysOnListener mListener = + new NfcControllerAlwaysOnListener(mNfcAdapter); + ControllerAlwaysOnListener mockListener1 = mock(ControllerAlwaysOnListener.class); + ControllerAlwaysOnListener mockListener2 = mock(ControllerAlwaysOnListener.class); + + // Verify that the state listener will not registered with the NFC Adapter + mListener.register(getExecutor(), mockListener1); + verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any()); + + // Register a second client and no any call to NFC Adapter + mListener.register(getExecutor(), mockListener2); + verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any()); + + // Unregister first listener, and no any call to NFC Adapter + mListener.unregister(mockListener1); + verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any()); + verify(mNfcAdapter, times(0)).unregisterControllerAlwaysOnListener(any()); + + // Unregister second listener, and no any call to NFC Adapter + mListener.unregister(mockListener2); + verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any()); + verify(mNfcAdapter, times(0)).unregisterControllerAlwaysOnListener(any()); + } + + @Test public void testRegister_RegisterUnregister() throws RemoteException { + doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported(); NfcControllerAlwaysOnListener mListener = new NfcControllerAlwaysOnListener(mNfcAdapter); ControllerAlwaysOnListener mockListener1 = mock(ControllerAlwaysOnListener.class); @@ -89,6 +119,7 @@ public class NfcControllerAlwaysOnListenerTest { @Test public void testRegister_FirstRegisterFails() throws RemoteException { + doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported(); NfcControllerAlwaysOnListener mListener = new NfcControllerAlwaysOnListener(mNfcAdapter); ControllerAlwaysOnListener mockListener1 = mock(ControllerAlwaysOnListener.class); @@ -116,6 +147,7 @@ public class NfcControllerAlwaysOnListenerTest { @Test public void testRegister_RegisterSameListenerTwice() throws RemoteException { + doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported(); NfcControllerAlwaysOnListener mListener = new NfcControllerAlwaysOnListener(mNfcAdapter); ControllerAlwaysOnListener mockListener = mock(ControllerAlwaysOnListener.class); @@ -132,7 +164,7 @@ public class NfcControllerAlwaysOnListenerTest { @Test public void testNotify_AllListenersNotified() throws RemoteException { - + doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported(); NfcControllerAlwaysOnListener listener = new NfcControllerAlwaysOnListener(mNfcAdapter); List<ControllerAlwaysOnListener> mockListeners = new ArrayList<>(); for (int i = 0; i < 10; i++) { @@ -149,7 +181,8 @@ public class NfcControllerAlwaysOnListenerTest { } @Test - public void testStateChange_CorrectValue() { + public void testStateChange_CorrectValue() throws RemoteException { + doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported(); runStateChangeValue(true, true); runStateChangeValue(false, false); diff --git a/data/etc/car/com.android.car.shell.xml b/data/etc/car/com.android.car.shell.xml index 578c46ee1006..d48d7515f22a 100644 --- a/data/etc/car/com.android.car.shell.xml +++ b/data/etc/car/com.android.car.shell.xml @@ -25,6 +25,7 @@ <permission name="android.car.permission.CAR_DIAGNOSTICS"/> <permission name="android.car.permission.CAR_DRIVING_STATE"/> <permission name="android.car.permission.CAR_POWER"/> + <permission name="android.car.permission.CONTROL_CAR_POWER_POLICY"/> <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/> <permission name="android.car.permission.CAR_TIRES"/> <permission name="android.car.permission.READ_CAR_STEERING"/> diff --git a/data/keyboards/Vendor_054c_Product_0268.kl b/data/keyboards/Vendor_054c_Product_0268.kl index b463dd84e75b..08d1c34f9eba 100644 --- a/data/keyboards/Vendor_054c_Product_0268.kl +++ b/data/keyboards/Vendor_054c_Product_0268.kl @@ -77,3 +77,11 @@ key 0x120 BUTTON_SELECT key 0x123 BUTTON_START # PS key key 0x2d0 BUTTON_MODE + +# SENSORs +sensor 0x00 ACCELEROMETER X +sensor 0x01 ACCELEROMETER Y +sensor 0x02 ACCELEROMETER Z +sensor 0x03 GYROSCOPE X +sensor 0x04 GYROSCOPE Y +sensor 0x05 GYROSCOPE Z diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl index 3d93f0fec800..d281b4bb531e 100644 --- a/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl +++ b/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl @@ -55,3 +55,11 @@ key 0x13a BUTTON_SELECT key 0x13b BUTTON_START # PS key key 0x13c BUTTON_MODE + +# SENSORs +sensor 0x00 ACCELEROMETER X +sensor 0x01 ACCELEROMETER Y +sensor 0x02 ACCELEROMETER Z +sensor 0x03 GYROSCOPE X +sensor 0x04 GYROSCOPE Y +sensor 0x05 GYROSCOPE Z diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl index 3d93f0fec800..d281b4bb531e 100644 --- a/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl +++ b/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl @@ -55,3 +55,11 @@ key 0x13a BUTTON_SELECT key 0x13b BUTTON_START # PS key key 0x13c BUTTON_MODE + +# SENSORs +sensor 0x00 ACCELEROMETER X +sensor 0x01 ACCELEROMETER Y +sensor 0x02 ACCELEROMETER Z +sensor 0x03 GYROSCOPE X +sensor 0x04 GYROSCOPE Y +sensor 0x05 GYROSCOPE Z diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl index 5fe35f7faefa..3eafea0f6c31 100644 --- a/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl +++ b/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl @@ -55,3 +55,11 @@ key 0x13a BUTTON_SELECT key 0x13b BUTTON_START # PS key key 0x13c BUTTON_MODE + +# SENSORs +sensor 0x00 ACCELEROMETER X +sensor 0x01 ACCELEROMETER Y +sensor 0x02 ACCELEROMETER Z +sensor 0x03 GYROSCOPE X +sensor 0x04 GYROSCOPE Y +sensor 0x05 GYROSCOPE Z diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 7f5b7520e76d..93a336e7a408 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -74,7 +74,7 @@ public class FontListParser { parser.setInput(in, null); parser.nextTag(); return readFamilies(parser, "/system/fonts/", new FontCustomizationParser.Result(), null, - 0, 0); + 0, 0, true); } /** @@ -116,7 +116,7 @@ public class FontListParser { parser.setInput(is, null); parser.nextTag(); return readFamilies(parser, systemFontDir, oemCustomization, updatableFontMap, - lastModifiedDate, configVersion); + lastModifiedDate, configVersion, false /* filter out the non-exising files */); } } @@ -126,7 +126,8 @@ public class FontListParser { @NonNull FontCustomizationParser.Result customization, @Nullable Map<String, File> updatableFontMap, long lastModifiedDate, - int configVersion) + int configVersion, + boolean allowNonExistingFile) throws XmlPullParserException, IOException { List<FontConfig.FontFamily> families = new ArrayList<>(); List<FontConfig.Alias> aliases = new ArrayList<>(customization.getAdditionalAliases()); @@ -139,7 +140,11 @@ public class FontListParser { if (parser.getEventType() != XmlPullParser.START_TAG) continue; String tag = parser.getName(); if (tag.equals("family")) { - FontConfig.FontFamily family = readFamily(parser, fontDir, updatableFontMap); + FontConfig.FontFamily family = readFamily(parser, fontDir, updatableFontMap, + allowNonExistingFile); + if (family == null) { + continue; + } String name = family.getName(); if (name == null || !oemNamedFamilies.containsKey(name)) { // The OEM customization overrides system named family. Skip if OEM @@ -165,9 +170,15 @@ public class FontListParser { /** * Read family tag in fonts.xml or oem_customization.xml + * + * @param parser An XML parser. + * @param fontDir a font directory name. + * @param updatableFontMap a updated font file map. + * @param allowNonExistingFile true to allow font file that doesn't exists + * @return a FontFamily instance. null if no font files are available in this FontFamily. */ - public static FontConfig.FontFamily readFamily(XmlPullParser parser, String fontDir, - @Nullable Map<String, File> updatableFontMap) + public static @Nullable FontConfig.FontFamily readFamily(XmlPullParser parser, String fontDir, + @Nullable Map<String, File> updatableFontMap, boolean allowNonExistingFile) throws XmlPullParserException, IOException { final String name = parser.getAttributeValue(null, "name"); final String lang = parser.getAttributeValue("", "lang"); @@ -177,7 +188,11 @@ public class FontListParser { if (parser.getEventType() != XmlPullParser.START_TAG) continue; final String tag = parser.getName(); if (tag.equals(TAG_FONT)) { - fonts.add(readFont(parser, fontDir, updatableFontMap)); + FontConfig.Font font = readFont(parser, fontDir, updatableFontMap, + allowNonExistingFile); + if (font != null) { + fonts.add(font); + } } else { skip(parser); } @@ -190,6 +205,9 @@ public class FontListParser { intVariant = FontConfig.FontFamily.VARIANT_ELEGANT; } } + if (fonts.isEmpty()) { + return null; + } return new FontConfig.FontFamily(fonts, name, LocaleList.forLanguageTags(lang), intVariant); } @@ -197,10 +215,11 @@ public class FontListParser { private static final Pattern FILENAME_WHITESPACE_PATTERN = Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$"); - private static FontConfig.Font readFont( + private static @Nullable FontConfig.Font readFont( @NonNull XmlPullParser parser, @NonNull String fontDir, - @Nullable Map<String, File> updatableFontMap) + @Nullable Map<String, File> updatableFontMap, + boolean allowNonExistingFile) throws XmlPullParserException, IOException { String indexStr = parser.getAttributeValue(null, ATTR_INDEX); @@ -253,7 +272,9 @@ public class FontListParser { File file = new File(filePath); - + if (!(allowNonExistingFile || file.isFile())) { + return null; + } return new FontConfig.Font(file, originalPath == null ? null : new File(originalPath), diff --git a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java index 20cd825fe306..423e66c7f657 100644 --- a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java @@ -48,6 +48,12 @@ public class ColorStateListDrawable extends Drawable implements Drawable.Callbac setColorStateList(colorStateList); } + private ColorStateListDrawable(@NonNull ColorStateListDrawableState state) { + mState = state; + initializeColorDrawable(); + onStateChange(getState()); + } + @Override public void draw(@NonNull Canvas canvas) { mColorDrawable.draw(canvas); @@ -286,11 +292,6 @@ public class ColorStateListDrawable extends Drawable implements Drawable.Callbac } } - private ColorStateListDrawable(@NonNull ColorStateListDrawableState state) { - mState = state; - initializeColorDrawable(); - } - private void initializeColorDrawable() { mColorDrawable = new ColorDrawable(); mColorDrawable.setCallback(this); diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java index e7c10819f679..2b4d5b45a009 100644 --- a/graphics/java/android/graphics/drawable/RippleShader.java +++ b/graphics/java/android/graphics/drawable/RippleShader.java @@ -115,7 +115,7 @@ final class RippleShader extends RuntimeShader { + " float fade = min(fadeIn, 1. - fadeOutRipple);\n" + " vec4 circle = in_color * (softCircle(p, center, in_maxRadius " + " * scaleIn, 0.2) * fade);\n" - + " float mask = in_hasMask == 1. ? sample(in_shader).a > 0. ? 1. : 0. : 1.;\n" + + " float mask = in_hasMask == 1. ? sample(in_shader, p).a > 0. ? 1. : 0. : 1.;\n" + " return mix(circle, in_sparkleColor, sparkle) * mask;\n" + "}"; private static final String SHADER = SHADER_UNIFORMS + SHADER_LIB + SHADER_MAIN; diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index 9298d9fcb9a7..4065bd110c7e 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -349,15 +349,19 @@ public class VectorDrawable extends Drawable { private final Rect mTmpBounds = new Rect(); public VectorDrawable() { - this(new VectorDrawableState(null), null); + this(null, null); } /** * The one constructor to rule them all. This is called by all public * constructors to set the state and initialize local properties. */ - private VectorDrawable(@NonNull VectorDrawableState state, @Nullable Resources res) { - mVectorState = state; + private VectorDrawable(@Nullable VectorDrawableState state, @Nullable Resources res) { + // As the mutable, not-thread-safe native instance is stored in VectorDrawableState, we + // need to always do a defensive copy even if mutate() isn't called. Otherwise + // draw() being called on 2 different VectorDrawable instances could still hit the same + // underlying native object. + mVectorState = new VectorDrawableState(state); updateLocalState(res); } diff --git a/graphics/java/android/graphics/fonts/FontCustomizationParser.java b/graphics/java/android/graphics/fonts/FontCustomizationParser.java index 42033ba017bf..9c01a4be381f 100644 --- a/graphics/java/android/graphics/fonts/FontCustomizationParser.java +++ b/graphics/java/android/graphics/fonts/FontCustomizationParser.java @@ -134,7 +134,7 @@ public class FontCustomizationParser { throw new IllegalArgumentException("customizationType must be specified"); } if (customizationType.equals("new-named-family")) { - out.add(FontListParser.readFamily(parser, fontDir, updatableFontMap)); + out.add(FontListParser.readFamily(parser, fontDir, updatableFontMap, false)); } else { throw new IllegalArgumentException("Unknown customizationType=" + customizationType); } diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java index bd72d45297c1..00219e7f28ac 100644 --- a/keystore/java/android/security/Authorization.java +++ b/keystore/java/android/security/Authorization.java @@ -74,16 +74,19 @@ public class Authorization { * @param locked - whether it is a lock (true) or unlock (false) event * @param syntheticPassword - if it is an unlock event with the password, pass the synthetic * password provided by the LockSettingService + * @param unlockingSids - KeyMint secure user IDs that should be permitted to unlock + * UNLOCKED_DEVICE_REQUIRED keys. * * @return 0 if successful or a {@code ResponseCode}. */ public static int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId, - @Nullable byte[] syntheticPassword) { + @Nullable byte[] syntheticPassword, @Nullable long[] unlockingSids) { try { if (locked) { - getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null); + getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null, unlockingSids); } else { - getService().onLockScreenEvent(LockScreenEvent.UNLOCK, userId, syntheticPassword); + getService().onLockScreenEvent( + LockScreenEvent.UNLOCK, userId, syntheticPassword, unlockingSids); } return 0; } catch (RemoteException | NullPointerException e) { diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java index ce9be6a7bba3..a0d5b004ff1c 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java @@ -69,21 +69,15 @@ class SampleExtensionImpl extends StubExtension { new ResourceConfigDisplayFeatureProducer(context) )); - mDevicePostureProducer.addDataChangedCallback(this::onDevicePostureChanged); + mDevicePostureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged); mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged); } - private void onDevicePostureChanged() { - updateDeviceState(new ExtensionDeviceState(getDevicePosture())); - - // Trigger a change in display features as the posture will be used in place of the feature - // state if the state is left unset by the producer. - onDisplayFeaturesChanged(); - } - - private int getDevicePosture() { + private int getFeatureState(DisplayFeature feature) { + Integer featureState = feature.getState(); Optional<Integer> posture = mDevicePostureProducer.getData(); - return posture.orElse(ExtensionDeviceState.POSTURE_UNKNOWN); + int fallbackPosture = posture.orElse(ExtensionFoldingFeature.STATE_FLAT); + return featureState == null ? fallbackPosture : featureState; } private void onDisplayFeaturesChanged() { @@ -115,17 +109,14 @@ class SampleExtensionImpl extends StubExtension { Optional<List<DisplayFeature>> storedFeatures = mDisplayFeatureProducer.getData(); if (storedFeatures.isPresent()) { - int posture = getDevicePosture(); for (DisplayFeature baseFeature : storedFeatures.get()) { Rect featureRect = baseFeature.getRect(); rotateRectToDisplayRotation(displayId, featureRect); transformToWindowSpaceRect(activity, featureRect); - Integer featureState = baseFeature.getState(); - features.add(new ExtensionFoldingFeature(featureRect, baseFeature.getType(), - featureState == null ? posture : featureState)); + getFeatureState(baseFeature))); } } return features; @@ -141,7 +132,6 @@ class SampleExtensionImpl extends StubExtension { mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded(); } - onDevicePostureChanged(); onDisplayFeaturesChanged(); } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java index b0895efc75a9..6a53efee0e74 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java @@ -31,7 +31,6 @@ abstract class StubExtension implements ExtensionInterface { private ExtensionCallback mExtensionCallback; private final Set<Activity> mWindowLayoutChangeListenerActivities = new HashSet<>(); - private boolean mDeviceStateChangeListenerRegistered; StubExtension() { } @@ -53,18 +52,6 @@ abstract class StubExtension implements ExtensionInterface { this.onListenersChanged(); } - @Override - public void onDeviceStateListenersChanged(boolean isEmpty) { - this.mDeviceStateChangeListenerRegistered = !isEmpty; - this.onListenersChanged(); - } - - void updateDeviceState(ExtensionDeviceState newState) { - if (this.mExtensionCallback != null) { - mExtensionCallback.onDeviceStateChanged(newState); - } - } - void updateWindowLayout(@NonNull Activity activity, @NonNull ExtensionWindowLayoutInfo newLayout) { if (this.mExtensionCallback != null) { @@ -78,8 +65,7 @@ abstract class StubExtension implements ExtensionInterface { } protected boolean hasListeners() { - return !mWindowLayoutChangeListenerActivities.isEmpty() - || mDeviceStateChangeListenerRegistered; + return !mWindowLayoutChangeListenerActivities.isEmpty(); } protected abstract void onListenersChanged(); diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar Binary files differindex 7b306b00afd9..be6652d43fb2 100644 --- a/libs/WindowManager/Jetpack/window-extensions-release.aar +++ b/libs/WindowManager/Jetpack/window-extensions-release.aar diff --git a/libs/WindowManager/Jetpack/window-sidecar-release.aar b/libs/WindowManager/Jetpack/window-sidecar-release.aar Binary files differindex 50f101d7d181..9d6baee0993a 100644 --- a/libs/WindowManager/Jetpack/window-sidecar-release.aar +++ b/libs/WindowManager/Jetpack/window-sidecar-release.aar diff --git a/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml index fe1ed4b6f726..fe6a8bd7643d 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml @@ -38,6 +38,7 @@ android:gravity="start" android:textAlignment="viewStart" android:text="@string/bubbles_user_education_title" + android:textColor="?android:attr/textColorPrimaryInverse" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/> <TextView @@ -48,6 +49,7 @@ android:gravity="start" android:textAlignment="viewStart" android:text="@string/bubbles_user_education_description" + android:textColor="?android:attr/textColorPrimaryInverse" android:fontFamily="@*android:string/config_bodyFontFamily" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/> </LinearLayout> diff --git a/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml index 8de06c7732d4..3d48e403b059 100644 --- a/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml +++ b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml @@ -41,6 +41,7 @@ android:ellipsize="end" android:gravity="start" android:textAlignment="viewStart" + android:textColor="?android:attr/textColorPrimaryInverse" android:text="@string/bubbles_user_education_manage_title" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/> @@ -55,6 +56,7 @@ android:ellipsize="end" android:gravity="start" android:textAlignment="viewStart" + android:textColor="?android:attr/textColorPrimaryInverse" android:fontFamily="@*android:string/config_bodyFontFamily" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/> diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml index a138fee32550..e8757b5d96f4 100644 --- a/libs/WindowManager/Shell/res/values/config.xml +++ b/libs/WindowManager/Shell/res/values/config.xml @@ -52,9 +52,6 @@ when the PIP menu is shown in center. --> <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string> - <!-- maximum animation duration for the icon when entering the starting window --> - <integer name="max_starting_window_intro_icon_anim_duration">1000</integer> - <!-- Animation duration when exit starting window: icon going away --> <integer name="starting_window_icon_exit_anim_duration">166</integer> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 3ced8d3ec6e7..ef731235a3c4 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -178,7 +178,9 @@ <dimen name="bubble_stack_user_education_side_inset">72dp</dimen> <!-- The width/height of the icon view on staring surface. --> - <dimen name="starting_surface_icon_size">108dp</dimen> + <dimen name="starting_surface_icon_size">160dp</dimen> + <!-- The default width/height of the icon on the spec of adaptive icon drawable. --> + <dimen name="default_icon_size">108dp</dimen> <!-- The width/height of the size compat restart button. --> <dimen name="size_compat_button_size">48dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java index b6d408afd703..eb82c6d597d4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java @@ -23,7 +23,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG; import android.app.ActivityManager; -import android.app.ActivityTaskManager; import android.graphics.Rect; import android.view.SurfaceControl; import android.window.WindowContainerToken; @@ -89,11 +88,11 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChan ProtoLog.v(WM_SHELL_TASK_ORG, "pair task1=%d task2=%d in AppPair=%s", task1.taskId, task2.taskId, this); - if ((!task1.isResizeable || !task2.isResizeable) - && !ActivityTaskManager.supportsNonResizableMultiWindow()) { + if (!task1.supportsMultiWindow || !task2.supportsMultiWindow) { ProtoLog.e(WM_SHELL_TASK_ORG, - "Can't pair unresizeable tasks task1.isResizeable=%b task1.isResizeable=%b", - task1.isResizeable, task2.isResizeable); + "Can't pair tasks that doesn't support multi window, " + + "task1.supportsMultiWindow=%b, task2.supportsMultiWindow=%b", + task1.supportsMultiWindow, task2.supportsMultiWindow); return false; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 4b037214fcdd..6a0f06192359 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -52,6 +52,7 @@ import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.PointF; +import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -70,6 +71,7 @@ import android.util.SparseSetArray; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +import android.window.WindowContainerTransaction; import androidx.annotation.MainThread; import androidx.annotation.Nullable; @@ -79,6 +81,8 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; +import com.android.wm.shell.common.DisplayChangeController; +import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerCallback; @@ -131,6 +135,7 @@ public class BubbleController { private final WindowManager mWindowManager; private final TaskStackListenerImpl mTaskStackListener; private final ShellTaskOrganizer mTaskOrganizer; + private final DisplayController mDisplayController; // Used to post to main UI thread private final ShellExecutor mMainExecutor; @@ -171,25 +176,21 @@ public class BubbleController { /** Whether or not the BubbleStackView has been added to the WindowManager. */ private boolean mAddedToWindowManager = false; - /** Last known orientation, used to detect orientation changes in {@link #onConfigChanged}. */ - private int mOrientation = Configuration.ORIENTATION_UNDEFINED; - - /** - * Last known screen density, used to detect display size changes in {@link #onConfigChanged}. - */ + /** Saved screen density, used to detect display size changes in {@link #onConfigChanged}. */ private int mDensityDpi = Configuration.DENSITY_DPI_UNDEFINED; - /** - * Last known font scale, used to detect font size changes in {@link #onConfigChanged}. - */ + /** Saved screen bounds, used to detect screen size changes in {@link #onConfigChanged}. **/ + private Rect mScreenBounds = new Rect(); + + /** Saved font scale, used to detect font size changes in {@link #onConfigChanged}. */ private float mFontScale = 0; - /** Last known direction, used to detect layout direction changes @link #onConfigChanged}. */ + /** Saved direction, used to detect layout direction changes @link #onConfigChanged}. */ private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED; private boolean mInflateSynchronously; - /** true when user is in status bar unlock shade. */ + /** True when user is in status bar unlock shade. */ private boolean mIsStatusBarShade = true; /** @@ -205,6 +206,7 @@ public class BubbleController { TaskStackListenerImpl taskStackListener, UiEventLogger uiEventLogger, ShellTaskOrganizer organizer, + DisplayController displayController, ShellExecutor mainExecutor, Handler mainHandler) { BubbleLogger logger = new BubbleLogger(uiEventLogger); @@ -213,7 +215,8 @@ public class BubbleController { return new BubbleController(context, data, synchronizer, floatingContentCoordinator, new BubbleDataRepository(context, launcherApps, mainExecutor), statusBarService, windowManager, windowManagerShellWrapper, launcherApps, - logger, taskStackListener, organizer, positioner, mainExecutor, mainHandler); + logger, taskStackListener, organizer, positioner, displayController, mainExecutor, + mainHandler); } /** @@ -233,6 +236,7 @@ public class BubbleController { TaskStackListenerImpl taskStackListener, ShellTaskOrganizer organizer, BubblePositioner positioner, + DisplayController displayController, ShellExecutor mainExecutor, Handler mainHandler) { mContext = context; @@ -256,6 +260,7 @@ public class BubbleController { mBubbleData = data; mSavedBubbleKeysPerUser = new SparseSetArray<>(); mBubbleIconFactory = new BubbleIconFactory(context); + mDisplayController = displayController; } public void initialize() { @@ -287,7 +292,6 @@ public class BubbleController { e.printStackTrace(); } - mBubbleData.setCurrentUserId(mCurrentUserId); mTaskOrganizer.addLocusIdListener((taskId, locus, visible) -> @@ -366,6 +370,23 @@ public class BubbleController { } } }); + + mDisplayController.addDisplayChangingController( + new DisplayChangeController.OnDisplayChangingListener() { + @Override + public void onRotateDisplay(int displayId, int fromRotation, int toRotation, + WindowContainerTransaction t) { + // This is triggered right before the rotation is applied + if (fromRotation != toRotation) { + mBubblePositioner.setRotation(toRotation); + if (mStackView != null) { + // Layout listener set on stackView will update the positioner + // once the rotation is applied + mStackView.onOrientationChanged(); + } + } + } + }); } @VisibleForTesting @@ -585,7 +606,7 @@ public class BubbleController { mStackView.addView(mBubbleScrim); mWindowManager.addView(mStackView, mWmLayoutParams); // Position info is dependent on us being attached to a window - mBubblePositioner.update(mOrientation); + mBubblePositioner.update(); } catch (IllegalStateException e) { // This means the stack has already been added. This shouldn't happen... e.printStackTrace(); @@ -682,16 +703,13 @@ public class BubbleController { private void onConfigChanged(Configuration newConfig) { if (mBubblePositioner != null) { - // This doesn't trigger any changes, always update it - mBubblePositioner.update(newConfig.orientation); + mBubblePositioner.update(); } if (mStackView != null && newConfig != null) { - if (newConfig.orientation != mOrientation) { - mOrientation = newConfig.orientation; - mStackView.onOrientationChanged(); - } - if (newConfig.densityDpi != mDensityDpi) { + if (newConfig.densityDpi != mDensityDpi + || !newConfig.windowConfiguration.getBounds().equals(mScreenBounds)) { mDensityDpi = newConfig.densityDpi; + mScreenBounds.set(newConfig.windowConfiguration.getBounds()); mBubbleIconFactory = new BubbleIconFactory(mContext); mStackView.onDisplaySizeChanged(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index 8434d668e153..6f526ecf2b62 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -575,6 +575,7 @@ public class BubbleData { Log.d(TAG, "Overflowing: " + bubble); } mLogger.logOverflowAdd(bubble, reason); + mOverflowBubbles.remove(bubble); mOverflowBubbles.add(0, bubble); mStateChange.addedOverflowBubble = bubble; bubble.stopInflation(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java index 8ee2b40d5985..f7c7285a7b6e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java @@ -220,18 +220,25 @@ public class BubbleOverflowContainerView extends LinearLayout { Log.d(TAG, "remove: " + toRemove); } toRemove.cleanupViews(); - final int i = mOverflowBubbles.indexOf(toRemove); + final int indexToRemove = mOverflowBubbles.indexOf(toRemove); mOverflowBubbles.remove(toRemove); - mAdapter.notifyItemRemoved(i); + mAdapter.notifyItemRemoved(indexToRemove); } Bubble toAdd = update.addedOverflowBubble; if (toAdd != null) { + final int indexToAdd = mOverflowBubbles.indexOf(toAdd); if (DEBUG_OVERFLOW) { - Log.d(TAG, "add: " + toAdd); + Log.d(TAG, "add: " + toAdd + " prevIndex: " + indexToAdd); + } + if (indexToAdd > 0) { + mOverflowBubbles.remove(toAdd); + mOverflowBubbles.add(0, toAdd); + mAdapter.notifyItemMoved(indexToAdd, 0); + } else { + mOverflowBubbles.add(0, toAdd); + mAdapter.notifyItemInserted(0); } - mOverflowBubbles.add(0, toAdd); - mAdapter.notifyItemInserted(0); } updateEmptyStateVisibility(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java index 1562e4bf6fcc..a81c2d8bef0a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java @@ -20,13 +20,13 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.content.Context; -import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Insets; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.util.Log; +import android.view.Surface; import android.view.View; import android.view.WindowInsets; import android.view.WindowManager; @@ -65,7 +65,7 @@ public class BubblePositioner { private Context mContext; private WindowManager mWindowManager; private Rect mPositionRect; - private int mOrientation; + private @Surface.Rotation int mRotation = Surface.ROTATION_0; private Insets mInsets; private int mBubbleSize; @@ -82,14 +82,18 @@ public class BubblePositioner { public BubblePositioner(Context context, WindowManager windowManager) { mContext = context; mWindowManager = windowManager; - update(Configuration.ORIENTATION_UNDEFINED); + update(); + } + + public void setRotation(int rotation) { + mRotation = rotation; } /** - * Updates orientation, available space, and inset information. Call this when config changes + * Available space and inset information. Call this when config changes * occur or when added to a window. */ - public void update(int orientation) { + public void update() { WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics(); if (windowMetrics == null) { return; @@ -102,12 +106,12 @@ public class BubblePositioner { if (BubbleDebugConfig.DEBUG_POSITIONER) { Log.w(TAG, "update positioner:" - + " landscape= " + (orientation == Configuration.ORIENTATION_LANDSCAPE) + + " rotation= " + mRotation + " insets: " + insets + " bounds: " + windowMetrics.getBounds() + " showingInTaskbar: " + mShowingInTaskbar); } - updateInternal(orientation, insets, windowMetrics.getBounds()); + updateInternal(mRotation, insets, windowMetrics.getBounds()); } /** @@ -122,12 +126,12 @@ public class BubblePositioner { mTaskbarIconSize = iconSize; mTaskbarPosition = taskbarPosition; mTaskbarSize = taskbarSize; - update(mOrientation); + update(); } @VisibleForTesting - public void updateInternal(int orientation, Insets insets, Rect bounds) { - mOrientation = orientation; + public void updateInternal(int rotation, Insets insets, Rect bounds) { + mRotation = rotation; mInsets = insets; mPositionRect = new Rect(bounds); @@ -189,7 +193,7 @@ public class BubblePositioner { * @return whether the device is in landscape orientation. */ public boolean isLandscape() { - return mOrientation == Configuration.ORIENTATION_LANDSCAPE; + return mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270; } /** @@ -200,8 +204,7 @@ public class BubblePositioner { * to the left or right side. */ public boolean showBubblesVertically() { - return mOrientation == Configuration.ORIENTATION_LANDSCAPE - || mShowingInTaskbar; + return isLandscape() || mShowingInTaskbar; } /** Size of the bubble account for badge & dot. */ 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 64bd245cb2ee..0f5d0eff7efa 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 @@ -884,6 +884,7 @@ public class BubbleStackView extends FrameLayout mOrientationChangedListener = (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + mPositioner.update(); onDisplaySizeChanged(); mExpandedAnimationController.updateResources(); mStackAnimationController.updateResources(); @@ -1214,11 +1215,12 @@ public class BubbleStackView extends FrameLayout updateExpandedViewTheme(); } - /** Respond to the phone being rotated by repositioning the stack and hiding any flyouts. */ + /** + * Respond to the phone being rotated by repositioning the stack and hiding any flyouts. + * This is called prior to the rotation occurring, any values that should be updated + * based on the new rotation should occur in {@link #mOrientationChangedListener}. + */ public void onOrientationChanged() { - Resources res = getContext().getResources(); - mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top); - mRelativeStackPositionBeforeRotation = new RelativeStackPosition( mPositioner.getRestingPosition(), mStackAnimationController.getAllowableStackPositionRegion()); @@ -1261,6 +1263,10 @@ public class BubbleStackView extends FrameLayout mStackAnimationController.updateResources(); mDismissView.updateResources(); mMagneticTarget.setMagneticFieldRadiusPx(mBubbleSize * 2); + mStackAnimationController.setStackPosition( + new RelativeStackPosition( + mPositioner.getRestingPosition(), + mStackAnimationController.getAllowableStackPositionRegion())); } @Override @@ -1598,6 +1604,7 @@ public class BubbleStackView extends FrameLayout // can start fresh. cancelAllExpandCollapseSwitchAnimations(); } + showManageMenu(false /* show */); // If we're expanded, screenshot the currently expanded bubble (before expanding the newly // selected bubble) so we can animate it out. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java index b9fdaa1ab1af..442e7a4c6796 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java @@ -110,6 +110,10 @@ public class DividerView extends FrameLayout implements View.OnTouchListener, return false; } + if (mDoubleTapDetector.onTouchEvent(event)) { + return true; + } + final int action = event.getAction() & MotionEvent.ACTION_MASK; final boolean isLandscape = isLandscape(); // Using raw xy to prevent lost track of motion events while moving divider bar. @@ -136,21 +140,22 @@ public class DividerView extends FrameLayout implements View.OnTouchListener, case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mVelocityTracker.addMovement(event); + releaseTouching(); + + if (!mMoving) break; + mVelocityTracker.computeCurrentVelocity(1000 /* units */); final float velocity = isLandscape ? mVelocityTracker.getXVelocity() : mVelocityTracker.getYVelocity(); - releaseTouching(); - mMoving = false; - final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos; final DividerSnapAlgorithm.SnapTarget snapTarget = mSplitLayout.findSnapTarget(position, velocity, false /* hardDismiss */); mSplitLayout.snapToTarget(position, snapTarget); + mMoving = false; break; } - mDoubleTapDetector.onTouchEvent(event); return true; } @@ -229,7 +234,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener, if (mSplitLayout != null) { mSplitLayout.onDoubleTappedDivider(); } - return false; + return true; } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index b64c796a1a43..d318a5aaef5c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -231,6 +231,7 @@ public class SplitLayout { } private void flingDividePosition(int from, int to) { + if (from == to) return; ValueAnimator animator = ValueAnimator .ofInt(from, to) .setDuration(250); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java index 57a9dd2ec6cc..23171bb9575c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java @@ -109,8 +109,9 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor return mSplits.mSplitScreenController.getSplitLayout(); } - private boolean isDividerVisible() { - return mSplits.mSplitScreenController.isDividerVisible(); + private boolean isDividerHidden() { + final DividerView view = mSplits.mSplitScreenController.getDividerView(); + return view == null || view.isHidden(); } private boolean getSecondaryHasFocus(int displayId) { @@ -143,7 +144,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor @ImeAnimationFlags public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop, boolean imeShouldShow, boolean imeIsFloating, SurfaceControl.Transaction t) { - if (!isDividerVisible()) { + if (isDividerHidden()) { return 0; } mHiddenTop = hiddenTop; @@ -263,7 +264,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor @Override public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) { - if (mAnimation != null || !isDividerVisible() || mPaused) { + if (mAnimation != null || isDividerHidden() || mPaused) { // Not synchronized with IME anymore, so return. return; } @@ -275,7 +276,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor @Override public void onImeEndPositioning(int displayId, boolean cancelled, SurfaceControl.Transaction t) { - if (mAnimation != null || !isDividerVisible() || mPaused) { + if (mAnimation != null || isDividerHidden() || mPaused) { // Not synchronized with IME anymore, so return. return; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java index a18d106abea4..60f7ee2941e2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java @@ -49,7 +49,6 @@ import android.view.VelocityTracker; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewConfiguration; -import android.view.ViewRootImpl; import android.view.ViewTreeObserver.InternalInsetsInfo; import android.view.ViewTreeObserver.OnComputeInternalInsetsListener; import android.view.WindowManager; @@ -524,9 +523,10 @@ public class DividerView extends FrameLayout implements OnTouchListener, case MotionEvent.ACTION_CANCEL: mVelocityTracker.addMovement(event); + if (!mMoving) break; + x = (int) event.getRawX(); y = (int) event.getRawY(); - mVelocityTracker.computeCurrentVelocity(1000); int position = calculatePosition(x, y); stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java index 27c56fd55e40..d9409ec2dc17 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java @@ -30,7 +30,6 @@ import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.ActivityTaskManager; import android.app.WindowConfiguration; import android.graphics.Rect; import android.os.IBinder; @@ -92,11 +91,10 @@ public class LegacySplitScreenTransitions implements Transitions.TransitionHandl // is nothing behind it. ((type == TRANSIT_CLOSE || type == TRANSIT_TO_BACK) && triggerTask.parentTaskId == mListener.mPrimary.taskId) - // if a non-resizable is launched when it is not supported in multi window, + // if an activity that is not supported in multi window mode is launched, // we also need to leave split-screen. || ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT) - && !triggerTask.isResizeable - && !ActivityTaskManager.supportsNonResizableMultiWindow()); + && !triggerTask.supportsMultiWindow); // In both cases, dismiss the primary if (shouldDismiss) { WindowManagerProxy.buildDismissSplit(out, mListener, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java index 5a2ef568d82a..1072845b35dd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java @@ -46,7 +46,6 @@ import com.android.wm.shell.transition.Transitions; import java.util.ArrayList; import java.util.List; -import java.util.function.BooleanSupplier; /** * Proxy to simplify calls into window manager/activity manager @@ -209,17 +208,10 @@ class WindowManagerProxy { return false; } ActivityManager.RunningTaskInfo topHomeTask = null; - // One-time lazy wrapper to avoid duplicated IPC in loop. Not store as class variable - // because the value can be changed at runtime. - final BooleanSupplier supportsNonResizableMultiWindow = - createSupportsNonResizableMultiWindowSupplier(); for (int i = rootTasks.size() - 1; i >= 0; --i) { final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i); - // Check whether to move resizeable task to split secondary. - // Also, we have an exception for non-resizable home because we will minimize to show - // it. - if (!rootTask.isResizeable && rootTask.topActivityType != ACTIVITY_TYPE_HOME - && !supportsNonResizableMultiWindow.getAsBoolean()) { + // Check whether the task can be moved to split secondary. + if (!rootTask.supportsMultiWindow && rootTask.topActivityType != ACTIVITY_TYPE_HOME) { continue; } // Only move fullscreen tasks to split secondary. @@ -364,21 +356,6 @@ class WindowManagerProxy { outWct.setFocusable(tiles.mPrimary.token, true /* focusable */); } - /** Creates a lazy wrapper to get whether it supports non-resizable in multi window. */ - private static BooleanSupplier createSupportsNonResizableMultiWindowSupplier() { - return new BooleanSupplier() { - private Boolean mSupportsNonResizableMultiWindow; - @Override - public boolean getAsBoolean() { - if (mSupportsNonResizableMultiWindow == null) { - mSupportsNonResizableMultiWindow = - ActivityTaskManager.supportsNonResizableMultiWindow(); - } - return mSupportsNonResizableMultiWindow; - } - }; - } - /** * Utility to apply a sync transaction serially with other sync transactions. * diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 58b3de466afc..04ec3917428e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -218,7 +218,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor); OneHandedState transitionState = new OneHandedState(); OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context, - windowManager, mainExecutor); + displayLayout, windowManager, mainExecutor); OneHandedAnimationController animationController = new OneHandedAnimationController(context); OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(timeoutHandler, @@ -453,6 +453,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> final DisplayLayout newDisplayLayout = mDisplayController.getDisplayLayout(displayId); mDisplayAreaOrganizer.setDisplayLayout(newDisplayLayout); mGestureHandler.onDisplayChanged(newDisplayLayout); + mTutorialHandler.onDisplayChanged(newDisplayLayout); } private ContentObserver getObserver(Runnable onChangeRunnable) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java index b445917fb90c..7a3f34d0e5a5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java @@ -33,6 +33,7 @@ import android.widget.FrameLayout; import androidx.annotation.NonNull; import com.android.wm.shell.R; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import java.io.PrintWriter; @@ -50,9 +51,10 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { private static final int MAX_TUTORIAL_SHOW_COUNT = 2; private final WindowManager mWindowManager; private final String mPackageName; - private final Rect mDisplaySize; + private final float mTutorialHeightRatio; private Context mContext; + private Rect mDisplayBounds; private View mTutorialView; private ContentResolver mContentResolver; private boolean mCanShowTutorial; @@ -94,23 +96,22 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { } }; - public OneHandedTutorialHandler(Context context, WindowManager windowManager, - ShellExecutor mainExecutor) { + public OneHandedTutorialHandler(Context context, DisplayLayout displayLayout, + WindowManager windowManager, ShellExecutor mainExecutor) { mContext = context; mWindowManager = windowManager; - mDisplaySize = windowManager.getCurrentWindowMetrics().getBounds(); mPackageName = context.getPackageName(); mContentResolver = context.getContentResolver(); - mCanShowTutorial = (Settings.Secure.getInt(mContentResolver, - Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT) - ? false : true; - mIsOneHandedMode = false; final float offsetPercentageConfig = context.getResources().getFraction( R.fraction.config_one_handed_offset, 1, 1); final int sysPropPercentageConfig = SystemProperties.getInt( ONE_HANDED_MODE_OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f)); - mTutorialAreaHeight = Math.round( - mDisplaySize.height() * (sysPropPercentageConfig / 100.0f)); + mTutorialHeightRatio = sysPropPercentageConfig / 100.0f; + onDisplayChanged(displayLayout); + mCanShowTutorial = (Settings.Secure.getInt(mContentResolver, + Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT) + ? false : true; + mIsOneHandedMode = false; mainExecutor.execute(() -> { recreateTutorialView(mContext); @@ -131,6 +132,20 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET; } + /** + * Called when onDisplayAdded() or onDisplayRemoved() callback + * @param displayLayout The latest {@link DisplayLayout} representing current displayId + */ + public void onDisplayChanged(DisplayLayout displayLayout) { + // Ensure the mDisplayBounds is portrait, due to OHM only support on portrait + if (displayLayout.height() > displayLayout.width()) { + mDisplayBounds = new Rect(0, 0, displayLayout.width(), displayLayout.height()); + } else { + mDisplayBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width()); + } + mTutorialAreaHeight = Math.round(mDisplayBounds.height() * mTutorialHeightRatio); + } + private void recreateTutorialView(Context context) { mTutorialView = LayoutInflater.from(context).inflate(R.layout.one_handed_tutorial, null); @@ -190,7 +205,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { */ private WindowManager.LayoutParams getTutorialTargetLayoutParams() { final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - mDisplaySize.width(), mTutorialAreaHeight, 0, 0, + mDisplayBounds.width(), mTutorialAreaHeight, 0, 0, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, @@ -207,8 +222,8 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { pw.println(TAG + " states: "); pw.print(innerPrefix + "mTriggerState="); pw.println(mTriggerState); - pw.print(innerPrefix + "mDisplaySize="); - pw.println(mDisplaySize); + pw.print(innerPrefix + "mDisplayBounds="); + pw.println(mDisplayBounds); pw.print(innerPrefix + "mTutorialAreaHeight="); pw.println(mTutorialAreaHeight); } 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 8ac9a7a479db..ca05ff47d507 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 @@ -427,36 +427,44 @@ public class PipAnimationController { Rect baseValue, Rect startValue, Rect endValue, Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, float startingAngle, @Surface.Rotation int rotationDelta) { + final boolean isOutPipDirection = isOutPipDirection(direction); + // Just for simplicity we'll interpolate between the source rect hint insets and empty // insets to calculate the window crop final Rect initialSourceValue; - if (isOutPipDirection(direction)) { + if (isOutPipDirection) { initialSourceValue = new Rect(endValue); } else { initialSourceValue = new Rect(baseValue); } - final Rect sourceHintRectInsets; - if (sourceHintRect == null) { - sourceHintRectInsets = null; - } else { - sourceHintRectInsets = new Rect(sourceHintRect.left - initialSourceValue.left, - sourceHintRect.top - initialSourceValue.top, - initialSourceValue.right - sourceHintRect.right, - initialSourceValue.bottom - sourceHintRect.bottom); - } - final Rect sourceInsets = new Rect(0, 0, 0, 0); - final Rect rotatedEndRect; + final Rect lastEndRect; + final Rect initialContainerRect; if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) { + lastEndRect = new Rect(endValue); + rotatedEndRect = new Rect(endValue); // Rotate the end bounds according to the rotation delta because the display will // be rotated to the same orientation. - rotatedEndRect = new Rect(endValue); - rotateBounds(rotatedEndRect, endValue, rotationDelta); + rotateBounds(rotatedEndRect, initialSourceValue, rotationDelta); + // Use the rect that has the same orientation as the hint rect. + initialContainerRect = isOutPipDirection ? rotatedEndRect : initialSourceValue; } else { - rotatedEndRect = null; + rotatedEndRect = lastEndRect = null; + initialContainerRect = initialSourceValue; } + final Rect sourceHintRectInsets; + if (sourceHintRect == null) { + sourceHintRectInsets = null; + } else { + sourceHintRectInsets = new Rect(sourceHintRect.left - initialContainerRect.left, + sourceHintRect.top - initialContainerRect.top, + initialContainerRect.right - sourceHintRect.right, + initialContainerRect.bottom - sourceHintRect.bottom); + } + final Rect zeroInsets = new Rect(0, 0, 0, 0); + // construct new Rect instances in case they are recycled return new PipTransitionAnimator<Rect>(taskInfo, leash, ANIM_TYPE_BOUNDS, endValue, new Rect(baseValue), new Rect(startValue), new Rect(endValue), @@ -472,8 +480,8 @@ public class PipAnimationController { final Rect end = getEndValue(); if (rotatedEndRect != null) { // Animate the bounds in a different orientation. It only happens when - // leaving PiP to fullscreen. - applyRotation(tx, leash, fraction, start, end, rotatedEndRect); + // switching between PiP and fullscreen. + applyRotation(tx, leash, fraction, start, end); return; } Rect bounds = mRectEvaluator.evaluate(fraction, start, end); @@ -481,20 +489,13 @@ public class PipAnimationController { setCurrentValue(bounds); if (inScaleTransition() || sourceHintRect == null) { - if (isOutPipDirection(direction)) { + if (isOutPipDirection) { getSurfaceTransactionHelper().scale(tx, leash, end, bounds); } else { getSurfaceTransactionHelper().scale(tx, leash, base, bounds, angle); } } else { - final Rect insets; - if (isOutPipDirection(direction)) { - insets = mInsetsEvaluator.evaluate(fraction, sourceHintRectInsets, - sourceInsets); - } else { - insets = mInsetsEvaluator.evaluate(fraction, sourceInsets, - sourceHintRectInsets); - } + final Rect insets = computeInsets(fraction); getSurfaceTransactionHelper().scaleAndCrop(tx, leash, initialSourceValue, bounds, insets); } @@ -502,9 +503,17 @@ public class PipAnimationController { } private void applyRotation(SurfaceControl.Transaction tx, SurfaceControl leash, - float fraction, Rect start, Rect end, Rect rotatedEndRect) { + float fraction, Rect start, Rect end) { + if (!end.equals(lastEndRect)) { + // If the end bounds are changed during animating (e.g. shelf height), the + // rotated end bounds also need to be updated. + rotatedEndRect.set(endValue); + rotateBounds(rotatedEndRect, initialSourceValue, rotationDelta); + lastEndRect.set(end); + } final Rect bounds = mRectEvaluator.evaluate(fraction, start, rotatedEndRect); setCurrentValue(bounds); + final Rect insets = computeInsets(fraction); final float degree, x, y; if (rotationDelta == ROTATION_90) { degree = 90 * fraction; @@ -515,11 +524,21 @@ public class PipAnimationController { x = fraction * (end.left - start.left) + start.left; y = fraction * (end.bottom - start.top) + start.top; } - getSurfaceTransactionHelper().rotateAndScaleWithCrop(tx, leash, bounds, - rotatedEndRect, degree, x, y); + getSurfaceTransactionHelper().rotateAndScaleWithCrop(tx, leash, + initialContainerRect, bounds, insets, degree, x, y, isOutPipDirection, + rotationDelta == ROTATION_270 /* clockwise */); tx.apply(); } + private Rect computeInsets(float fraction) { + if (sourceHintRectInsets == null) { + return zeroInsets; + } + final Rect startRect = isOutPipDirection ? sourceHintRectInsets : zeroInsets; + final Rect endRect = isOutPipDirection ? zeroInsets : sourceHintRectInsets; + return mInsetsEvaluator.evaluate(fraction, startRect, endRect); + } + @Override void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) { getSurfaceTransactionHelper() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java index 0528e4d88374..dd30137813e5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java @@ -109,13 +109,14 @@ public class PipSnapAlgorithm { * consideration. */ public void applySnapFraction(Rect stackBounds, Rect movementBounds, float snapFraction, - @PipBoundsState.StashType int stashType, int stashOffset, Rect displayBounds) { + @PipBoundsState.StashType int stashType, int stashOffset, Rect displayBounds, + Rect insetBounds) { applySnapFraction(stackBounds, movementBounds, snapFraction); if (stashType != STASH_TYPE_NONE) { stackBounds.offsetTo(stashType == STASH_TYPE_LEFT - ? stashOffset - stackBounds.width() - : displayBounds.right - stashOffset, + ? stashOffset - stackBounds.width() + insetBounds.left + : displayBounds.right - stashOffset - insetBounds.right, stackBounds.top); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java index 3dd97f565179..2b795390adda 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java @@ -137,23 +137,41 @@ public class PipSurfaceTransactionHelper { * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper rotateAndScaleWithCrop(SurfaceControl.Transaction tx, - SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, float degrees, - float positionX, float positionY) { + SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, Rect insets, + float degrees, float positionX, float positionY, boolean isExpanding, + boolean clockwise) { mTmpDestinationRect.set(sourceBounds); - final int dw = destinationBounds.width(); - final int dh = destinationBounds.height(); + mTmpDestinationRect.inset(insets); + final int srcW = mTmpDestinationRect.width(); + final int srcH = mTmpDestinationRect.height(); + final int destW = destinationBounds.width(); + final int destH = destinationBounds.height(); // Scale by the short side so there won't be empty area if the aspect ratio of source and // destination are different. - final float scale = dw <= dh - ? (float) sourceBounds.width() / dw - : (float) sourceBounds.height() / dh; + final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH; + final Rect crop = mTmpDestinationRect; + crop.set(0, 0, destW, destH); // Inverse scale for crop to fit in screen coordinates. - mTmpDestinationRect.scale(1 / scale); - mTmpTransform.setRotate(degrees); - mTmpTransform.postScale(scale, scale); + crop.scale(1 / scale); + crop.offset(insets.left, insets.top); + if (isExpanding) { + // Expand bounds (shrink insets) in source orientation. + positionX -= insets.left * scale; + positionY -= insets.top * scale; + } else { + // Shrink bounds (expand insets) in destination orientation. + if (clockwise) { + positionX -= insets.top * scale; + positionY -= insets.left * scale; + } else { + positionX += insets.top * scale; + positionY += insets.left * scale; + } + } + mTmpTransform.setScale(scale, scale); + mTmpTransform.postRotate(degrees); mTmpTransform.postTranslate(positionX, positionY); - tx.setMatrix(leash, mTmpTransform, mTmpFloat9) - .setWindowCrop(leash, mTmpDestinationRect.width(), mTmpDestinationRect.height()); + tx.setMatrix(leash, mTmpTransform, mTmpFloat9).setWindowCrop(leash, crop); return this; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index e66be66c8ef4..4ce6c9e35e9e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -20,6 +20,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.util.RotationUtils.deltaRotation; +import static android.util.RotationUtils.rotateBounds; import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP; import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString; @@ -50,8 +52,10 @@ import android.app.TaskInfo; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; +import android.content.res.Configuration; import android.graphics.Rect; import android.os.RemoteException; +import android.os.SystemClock; import android.util.Log; import android.util.Rational; import android.view.Display; @@ -94,6 +98,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, DisplayController.OnDisplaysChangedListener { private static final String TAG = PipTaskOrganizer.class.getSimpleName(); private static final boolean DEBUG = false; + /** + * The alpha type is set for swiping to home. But the swiped task may not enter PiP. And if + * another task enters PiP by non-swipe ways, e.g. call API in foreground or switch to 3-button + * navigation, then the alpha type is unexpected. + */ + private static final int ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS = 1000; // Not a complete set of states but serves what we want right now. private enum State { @@ -127,6 +137,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } } + private final Context mContext; private final SyncTransactionQueue mSyncTransactionQueue; private final PipBoundsState mPipBoundsState; private final PipBoundsAlgorithm mPipBoundsAlgorithm; @@ -160,8 +171,20 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, public void onPipAnimationEnd(TaskInfo taskInfo, SurfaceControl.Transaction tx, PipAnimationController.PipTransitionAnimator animator) { final int direction = animator.getTransitionDirection(); - finishResize(tx, animator.getDestinationBounds(), direction, - animator.getAnimationType()); + final int animationType = animator.getAnimationType(); + final Rect destinationBounds = animator.getDestinationBounds(); + if (mWaitForFixedRotation && animationType == ANIM_TYPE_BOUNDS + && direction == TRANSITION_DIRECTION_TO_PIP) { + // Notify the display to continue the deferred orientation change. + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.scheduleFinishEnterPip(mToken, destinationBounds); + mTaskOrganizer.applyTransaction(wct); + // The final task bounds will be applied by onFixedRotationFinished so that all + // coordinates are in new rotation. + mDeferredAnimEndTransaction = tx; + return; + } + finishResize(tx, destinationBounds, direction, animationType); sendOnPipTransitionFinished(direction); if (direction == TRANSITION_DIRECTION_TO_PIP) { // TODO (b//169221267): Add jank listener for transactions without buffer updates. @@ -186,10 +209,18 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private SurfaceControl mLeash; private State mState = State.UNDEFINED; private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS; + private long mLastOneShotAlphaAnimationTime; private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; private PictureInPictureParams mPictureInPictureParams; private IntConsumer mOnDisplayIdChangeCallback; + /** + * The end transaction of PiP animation for switching between PiP and fullscreen with + * orientation change. The transaction should be applied after the display is rotated. + */ + private SurfaceControl.Transaction mDeferredAnimEndTransaction; + /** Whether the existing PiP is hidden by alpha. */ + private boolean mHasFadeOut; /** * If set to {@code true}, the entering animation will be skipped and we will wait for @@ -203,6 +234,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, */ private @Surface.Rotation int mNextRotation; + private @Surface.Rotation int mCurrentRotation; + /** * If set to {@code true}, no entering PiP transition would be kicked off and most likely * it's due to the fact that Launcher is handling the transition directly when swiping @@ -224,6 +257,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @NonNull PipUiEventLogger pipUiEventLogger, @NonNull ShellTaskOrganizer shellTaskOrganizer, @ShellMainThread ShellExecutor mainExecutor) { + mContext = context; mSyncTransactionQueue = syncTransactionQueue; mPipBoundsState = pipBoundsState; mPipBoundsAlgorithm = boundsHandler; @@ -261,10 +295,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return mState.isInPip(); } - public boolean isDeferringEnterPipAnimation() { - return mState.isInPip() && mWaitForFixedRotation; - } - /** * Returns whether the entry animation is waiting to be started. */ @@ -286,6 +316,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, */ public void setOneShotAnimationType(@PipAnimationController.AnimationType int animationType) { mOneShotAnimationType = animationType; + if (animationType == ANIM_TYPE_ALPHA) { + mLastOneShotAlphaAnimationTime = SystemClock.uptimeMillis(); + } } /** @@ -297,9 +330,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mInSwipePipToHomeTransition = true; sendOnPipTransitionStarted(TRANSITION_DIRECTION_TO_PIP); setBoundsStateForEntry(componentName, pictureInPictureParams, activityInfo); - // disable the conflicting transaction from fixed rotation, see also - // onFixedRotationStarted and onFixedRotationFinished - mWaitForFixedRotation = false; return mPipBoundsAlgorithm.getEntryDestinationBounds(); } @@ -355,6 +385,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, : WINDOWING_MODE_FULLSCREEN); wct.setBounds(mToken, destinationBounds); wct.setBoundsChangeTransaction(mToken, tx); + // Set the exiting state first so if there is fixed rotation later, the running animation + // won't be interrupted by alpha animation for existing PiP. + mState = State.EXITING_PIP; mSyncTransactionQueue.queue(wct); mSyncTransactionQueue.runInSync(t -> { // Make sure to grab the latest source hint rect as it could have been @@ -362,9 +395,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( mPictureInPictureParams, destinationBounds); final PipAnimationController.PipTransitionAnimator<?> animator = - scheduleAnimateResizePip(mPipBoundsState.getBounds(), destinationBounds, - 0 /* startingAngle */, sourceHintRect, direction, - animationDurationMs, null /* updateBoundsCallback */); + animateResizePip(mPipBoundsState.getBounds(), destinationBounds, sourceHintRect, + direction, animationDurationMs, 0 /* startingAngle */); if (animator != null) { // Even though the animation was started above, re-apply the transaction for the // first frame using the SurfaceControl.Transaction supplied by the @@ -374,7 +406,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // hint during expansion that causes a visible jank/flash. See b/184166183. animator.applySurfaceControlTransaction(mLeash, t, FRACTION_START); } - mState = State.EXITING_PIP; }); } @@ -447,29 +478,22 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } if (mInSwipePipToHomeTransition) { - final Rect destinationBounds = mPipBoundsState.getBounds(); - final SurfaceControl.Transaction tx = - mSurfaceControlTransactionFactory.getTransaction(); - mSurfaceTransactionHelper.resetScale(tx, mLeash, destinationBounds); - mSurfaceTransactionHelper.crop(tx, mLeash, destinationBounds); - // animation is finished in the Launcher and here we directly apply the final touch. - applyEnterPipSyncTransaction(destinationBounds, () -> { - // ensure menu's settled in its final bounds first - finishResizeForMenu(destinationBounds); - sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP); - }, tx); - mInSwipePipToHomeTransition = false; + if (!mWaitForFixedRotation) { + onEndOfSwipePipToHomeTransition(); + } else { + Log.d(TAG, "Defer onTaskAppeared-SwipePipToHome until end of fixed rotation."); + } return; } + if (mOneShotAnimationType == ANIM_TYPE_ALPHA + && SystemClock.uptimeMillis() - mLastOneShotAlphaAnimationTime + > ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS) { + Log.d(TAG, "Alpha animation is expired. Use bounds animation."); + mOneShotAnimationType = ANIM_TYPE_BOUNDS; + } if (mWaitForFixedRotation) { - if (DEBUG) Log.d(TAG, "Defer entering PiP animation, fixed rotation is ongoing"); - // if deferred, hide the surface till fixed rotation is completed - final SurfaceControl.Transaction tx = - mSurfaceControlTransactionFactory.getTransaction(); - tx.setAlpha(mLeash, 0f); - tx.show(mLeash); - tx.apply(); + onTaskAppearedWithFixedRotation(); return; } @@ -500,6 +524,27 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } } + private void onTaskAppearedWithFixedRotation() { + if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { + Log.d(TAG, "Defer entering PiP alpha animation, fixed rotation is ongoing"); + // If deferred, hide the surface till fixed rotation is completed. + final SurfaceControl.Transaction tx = + mSurfaceControlTransactionFactory.getTransaction(); + tx.setAlpha(mLeash, 0f); + tx.show(mLeash); + tx.apply(); + mOneShotAnimationType = ANIM_TYPE_BOUNDS; + return; + } + final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); + final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( + mPictureInPictureParams, currentBounds); + final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); + animateResizePip(currentBounds, destinationBounds, sourceHintRect, + TRANSITION_DIRECTION_TO_PIP, mEnterAnimationDuration, 0 /* startingAngle */); + mState = State.ENTERING_PIP; + } + /** * Called when the display rotation handling is skipped (e.g. when rotation happens while in * the middle of an entry transition). @@ -536,6 +581,20 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, }, null /* boundsChangeTransaction */); } + private void onEndOfSwipePipToHomeTransition() { + final Rect destinationBounds = mPipBoundsState.getBounds(); + final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); + mSurfaceTransactionHelper.resetScale(tx, mLeash, destinationBounds); + mSurfaceTransactionHelper.crop(tx, mLeash, destinationBounds); + // The animation is finished in the Launcher and here we directly apply the final touch. + applyEnterPipSyncTransaction(destinationBounds, () -> { + // Ensure menu's settled in its final bounds first. + finishResizeForMenu(destinationBounds); + sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP); + }, tx); + mInSwipePipToHomeTransition = false; + } + private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable, @Nullable SurfaceControl.Transaction boundsChangeTransaction) { // PiP menu is attached late in the process here to avoid any artifacts on the leash @@ -547,7 +606,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, if (boundsChangeTransaction != null) { wct.setBoundsChangeTransaction(mToken, boundsChangeTransaction); } - wct.scheduleFinishEnterPip(mToken, destinationBounds); mSyncTransactionQueue.queue(wct); if (runnable != null) { mSyncTransactionQueue.runInSync(t -> runnable.run()); @@ -600,7 +658,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, Log.wtf(TAG, "Unrecognized token: " + token); return; } - mWaitForFixedRotation = false; + clearWaitForFixedRotation(); mInSwipePipToHomeTransition = false; mPictureInPictureParams = null; mState = State.UNDEFINED; @@ -617,8 +675,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken"); - if (mState != State.ENTERED_PIP) { + if (mState != State.ENTERED_PIP && mState != State.EXITING_PIP) { Log.d(TAG, "Defer onTaskInfoChange in current state: " + mState); + // Defer applying PiP parameters if the task is entering PiP to avoid disturbing + // the animation. mDeferredTaskInfo = info; return; } @@ -648,16 +708,60 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, public void onFixedRotationStarted(int displayId, int newRotation) { mNextRotation = newRotation; mWaitForFixedRotation = true; + + if (mState.isInPip()) { + // Fade out the existing PiP to avoid jump cut during seamless rotation. + fadeExistingPip(false /* show */); + } } @Override public void onFixedRotationFinished(int displayId) { - if (mWaitForFixedRotation && mState.isInPip()) { - final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); - // schedule a regular animation to ensure all the callbacks are still being sent - enterPipWithAlphaAnimation(destinationBounds, 0 /* durationMs */); + if (!mWaitForFixedRotation) { + return; } + if (mState == State.TASK_APPEARED) { + if (mInSwipePipToHomeTransition) { + onEndOfSwipePipToHomeTransition(); + } else { + // Schedule a regular animation to ensure all the callbacks are still being sent. + enterPipWithAlphaAnimation(mPipBoundsAlgorithm.getEntryDestinationBounds(), + mEnterAnimationDuration); + } + } else if (mState == State.ENTERED_PIP && mHasFadeOut) { + fadeExistingPip(true /* show */); + } else if (mState == State.ENTERING_PIP && mDeferredAnimEndTransaction != null) { + final PipAnimationController.PipTransitionAnimator<?> animator = + mPipAnimationController.getCurrentAnimator(); + final Rect destinationBounds = animator.getDestinationBounds(); + mPipBoundsState.setBounds(destinationBounds); + applyEnterPipSyncTransaction(destinationBounds, () -> { + finishResizeForMenu(destinationBounds); + sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP); + }, mDeferredAnimEndTransaction); + } + clearWaitForFixedRotation(); + } + + private void fadeExistingPip(boolean show) { + final float alphaStart = show ? 0 : 1; + final float alphaEnd = show ? 1 : 0; + mPipAnimationController + .getAnimator(mTaskInfo, mLeash, mPipBoundsState.getBounds(), alphaStart, alphaEnd) + .setTransitionDirection(TRANSITION_DIRECTION_SAME) + .setDuration(show ? mEnterAnimationDuration : mExitAnimationDuration) + .start(); + mHasFadeOut = !show; + } + + private void clearWaitForFixedRotation() { mWaitForFixedRotation = false; + mDeferredAnimEndTransaction = null; + } + + @Override + public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { + mCurrentRotation = newConfig.windowConfiguration.getRotation(); } /** @@ -686,7 +790,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mPipAnimationController.getCurrentAnimator(); if (animator == null || !animator.isRunning() || animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) { - if (mState.isInPip() && fromRotation && !mWaitForFixedRotation) { + final boolean rotatingPip = mState.isInPip() && fromRotation; + if (rotatingPip && mWaitForFixedRotation && mHasFadeOut) { + // The position will be used by fade-in animation when the fixed rotation is done. + mPipBoundsState.setBounds(destinationBoundsOut); + } else if (rotatingPip) { // Update bounds state to final destination first. It's important to do this // before finishing & cancelling the transition animation so that the MotionHelper // bounds are synchronized to the destination bounds when the animation ends. @@ -737,7 +845,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final Rect newDestinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); if (newDestinationBounds.equals(currentDestinationBounds)) return; if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) { - animator.updateEndValue(newDestinationBounds); + if (mWaitForFixedRotation) { + // The new destination bounds are in next rotation (DisplayLayout has been rotated + // in computeRotatedBounds). The animation runs in previous rotation so the end + // bounds need to be transformed. + final Rect displayBounds = mPipBoundsState.getDisplayBounds(); + final Rect rotatedEndBounds = new Rect(newDestinationBounds); + rotateBounds(rotatedEndBounds, displayBounds, mNextRotation, mCurrentRotation); + animator.updateEndValue(rotatedEndBounds); + } else { + animator.updateEndValue(newDestinationBounds); + } } animator.setDestinationBounds(newDestinationBounds); destinationBoundsOut.set(newDestinationBounds); @@ -1050,7 +1168,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // activity windowing mode set by WM, and set the task bounds to the final bounds taskBounds = destinationBounds; wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); - wct.scheduleFinishEnterPip(mToken, destinationBounds); } else if (isOutPipDirection(direction)) { // If we are animating to fullscreen or split screen, then we need to reset the // override bounds on the task to ensure that the task "matches" the parent's bounds. @@ -1096,8 +1213,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return null; } final int rotationDelta = mWaitForFixedRotation - ? ((mNextRotation - mPipBoundsState.getDisplayLayout().rotation()) + 4) % 4 + ? deltaRotation(mCurrentRotation, mNextRotation) : Surface.ROTATION_0; + if (rotationDelta != Surface.ROTATION_0) { + sourceHintRect = computeRotatedBounds(rotationDelta, direction, destinationBounds, + sourceHintRect); + } Rect baseBounds = direction == TRANSITION_DIRECTION_SNAP_AFTER_RESIZE ? mPipBoundsState.getBounds() : currentBounds; final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController @@ -1107,9 +1228,35 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, .setPipAnimationCallback(mPipAnimationCallback) .setDuration(durationMs) .start(); + if (rotationDelta != Surface.ROTATION_0 && direction == TRANSITION_DIRECTION_TO_PIP) { + // The destination bounds are used for the end rect of animation and the final bounds + // after animation finishes. So after the animation is started, the destination bounds + // can be updated to new rotation (computeRotatedBounds has changed the DisplayLayout + // without affecting the animation. + animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds()); + } return animator; } + /** Computes destination bounds in old rotation and returns source hint rect if available. */ + private @Nullable Rect computeRotatedBounds(int rotationDelta, int direction, + Rect outDestinationBounds, Rect sourceHintRect) { + if (direction == TRANSITION_DIRECTION_TO_PIP) { + mPipBoundsState.getDisplayLayout().rotateTo(mContext.getResources(), mNextRotation); + final Rect displayBounds = mPipBoundsState.getDisplayBounds(); + outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds()); + // Transform the destination bounds to current display coordinates. + rotateBounds(outDestinationBounds, displayBounds, mNextRotation, mCurrentRotation); + } else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) { + final Rect rotatedDestinationBounds = new Rect(outDestinationBounds); + rotateBounds(rotatedDestinationBounds, mPipBoundsState.getDisplayBounds(), + rotationDelta); + return PipBoundsAlgorithm.getValidSourceHintRect(mPictureInPictureParams, + rotatedDestinationBounds); + } + return sourceHintRect; + } + /** * Sync with {@link LegacySplitScreenController} on destination bounds if PiP is going to split * screen. 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 f505e60de61e..fa5caf00dde7 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 @@ -114,13 +114,17 @@ public class PipController implements PipTransitionController.PipTransitionCallb */ private final DisplayChangeController.OnDisplayChangingListener mRotationController = ( int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> { - if (!mPipTaskOrganizer.isInPip() - || mPipBoundsState.getDisplayLayout().rotation() == toRotation - || mPipTaskOrganizer.isDeferringEnterPipAnimation() - || mPipTaskOrganizer.isEntryScheduled()) { - // Skip if the same rotation has been set or we aren't in PIP or haven't actually - // entered PIP yet. We still need to update the display layout in the bounds handler - // in this case. + if (mPipBoundsState.getDisplayLayout().rotation() == toRotation) { + // The same rotation may have been set by auto PiP-able or fixed rotation. So notify + // the change with fromRotation=false to apply the rotated destination bounds from + // PipTaskOrganizer#onMovementBoundsChanged. + updateMovementBounds(null, false /* fromRotation */, + false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t); + return; + } + if (!mPipTaskOrganizer.isInPip() || mPipTaskOrganizer.isEntryScheduled()) { + // Update display layout and bounds handler if we aren't in PIP or haven't actually + // entered PIP yet. onDisplayRotationChangedNotInPip(mContext, toRotation); // do not forget to update the movement bounds as well. updateMovementBounds(mPipBoundsState.getNormalBounds(), true /* fromRotation */, @@ -460,7 +464,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb pipSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds, snapFraction, mPipBoundsState.getStashedState(), mPipBoundsState.getStashOffset(), - mPipBoundsState.getDisplayBounds()); + mPipBoundsState.getDisplayBounds(), + mPipBoundsState.getDisplayLayout().stableInsets()); mTouchHandler.getMotionHelper().movePip(postChangeStackBounds); } else { @@ -664,7 +669,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb postChangeStackBounds, false /* adjustForIme */); pipSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds, snapFraction, mPipBoundsState.getStashedState(), mPipBoundsState.getStashOffset(), - mPipBoundsState.getDisplayBounds()); + mPipBoundsState.getDisplayBounds(), + mPipBoundsState.getDisplayLayout().stableInsets()); mPipBoundsAlgorithm.getInsetBounds(outInsetBounds); outBounds.set(postChangeStackBounds); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java index 10625617a379..67467eda51d0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java @@ -406,11 +406,14 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, .flingThenSpring( FloatProperties.RECT_Y, velocityY, mFlingConfigY, mSpringConfig); + final Rect insetBounds = mPipBoundsState.getDisplayLayout().stableInsets(); final float leftEdge = isStash ? mPipBoundsState.getStashOffset() - mPipBoundsState.getBounds().width() + + insetBounds.left : mPipBoundsState.getMovementBounds().left; final float rightEdge = isStash ? mPipBoundsState.getDisplayBounds().right - mPipBoundsState.getStashOffset() + - insetBounds.right : mPipBoundsState.getMovementBounds().right; final float xEndValue = velocityX < 0 ? leftEdge : rightEdge; @@ -483,7 +486,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction, mPipBoundsState.getStashedState(), mPipBoundsState.getStashOffset(), - mPipBoundsState.getDisplayBounds()); + mPipBoundsState.getDisplayBounds(), + mPipBoundsState.getDisplayLayout().stableInsets()); if (immediate) { movePip(normalBounds); @@ -529,10 +533,13 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, mFlingConfigY = new PhysicsAnimator.FlingConfig(DEFAULT_FRICTION, mPipBoundsState.getMovementBounds().top, mPipBoundsState.getMovementBounds().bottom); + final Rect insetBounds = mPipBoundsState.getDisplayLayout().stableInsets(); mStashConfigX = new PhysicsAnimator.FlingConfig( DEFAULT_FRICTION, - mPipBoundsState.getStashOffset() - mPipBoundsState.getBounds().width(), - mPipBoundsState.getDisplayBounds().right - mPipBoundsState.getStashOffset()); + mPipBoundsState.getStashOffset() - mPipBoundsState.getBounds().width() + + insetBounds.left, + mPipBoundsState.getDisplayBounds().right - mPipBoundsState.getStashOffset() + - insetBounds.right); } private void startBoundsAnimator(float toX, float toY) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java index 0a148c413c0f..c2ec1c55a59f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java @@ -232,7 +232,8 @@ public class PipResizeGestureHandler { } } - private void onInputEvent(InputEvent ev) { + @VisibleForTesting + void onInputEvent(InputEvent ev) { // Don't allow resize when PiP is stashed. if (mPipBoundsState.isStashed()) { return; @@ -366,7 +367,8 @@ public class PipResizeGestureHandler { return mIsSysUiStateValid; } - private void onPinchResize(MotionEvent ev) { + @VisibleForTesting + void onPinchResize(MotionEvent ev) { int action = ev.getActionMasked(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { @@ -411,7 +413,7 @@ public class PipResizeGestureHandler { if (!mThresholdCrossed && (distanceBetween(mDownSecondPoint, mLastSecondPoint) > mTouchSlop || distanceBetween(mDownPoint, mLastPoint) > mTouchSlop)) { - mInputMonitor.pilferPointers(); + pilferPointers(); mThresholdCrossed = true; // Reset the down to begin resizing from this point mDownPoint.set(mLastPoint); @@ -548,6 +550,17 @@ public class PipResizeGestureHandler { return mUserResizeBounds; } + @VisibleForTesting + Rect getLastResizeBounds() { + return mLastResizeBounds; + } + + @VisibleForTesting + void pilferPointers() { + mInputMonitor.pilferPointers(); + } + + @VisibleForTesting public void updateMaxSize(int maxX, int maxY) { mMaxSize.set(maxX, maxY); } 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 c91a92ad3242..efaa2696cbeb 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 @@ -337,6 +337,7 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, final WindowContainerTransaction wct = new WindowContainerTransaction(); // Make the stages adjacent to each other so they occlude what's behind them. wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token); + wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token); mTaskOrganizer.applyTransaction(wct); } } @@ -346,6 +347,7 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, final WindowContainerTransaction wct = new WindowContainerTransaction(); // Deactivate the main stage if it no longer has a root task. mMainStage.deactivate(wct); + wct.clearLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token); mTaskOrganizer.applyTransaction(wct); } } @@ -449,6 +451,7 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, final WindowContainerTransaction wct = new WindowContainerTransaction(); // Make sure the main stage is active. mMainStage.activate(getMainStageBounds(), wct); + mSideStage.setBounds(getSideStageBounds(), wct); mTaskOrganizer.applyTransaction(wct); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java index ccf062ea3e9d..1d3a60b8193d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java @@ -18,7 +18,6 @@ package com.android.wm.shell.startingsurface; import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; -import static android.os.UserHandle.getUserHandleForUid; import android.annotation.ColorInt; import android.annotation.NonNull; @@ -68,11 +67,12 @@ public class SplashscreenContentDrawer { // For example, an icon with the foreground 108*108 opaque pixels and it's background // also 108*108 pixels, then do not enlarge this icon if only need to show foreground icon. private static final float ENLARGE_FOREGROUND_ICON_THRESHOLD = (72f * 72f) / (108f * 108f); + private static final float NO_BACKGROUND_SCALE = 1.3f; private final Context mContext; private final IconProvider mIconProvider; - private final int mMaxAnimatableIconDuration; private int mIconSize; + private int mDefaultIconSize; private int mBrandingImageWidth; private int mBrandingImageHeight; private final int mAppRevealDuration; @@ -84,11 +84,10 @@ public class SplashscreenContentDrawer { private final SplashScreenWindowAttrs mTmpAttrs = new SplashScreenWindowAttrs(); private final Handler mSplashscreenWorkerHandler; - SplashscreenContentDrawer(Context context, int maxAnimatableIconDuration, - int iconExitAnimDuration, int appRevealAnimDuration, TransactionPool pool) { + SplashscreenContentDrawer(Context context, int iconExitAnimDuration, int appRevealAnimDuration, + TransactionPool pool) { mContext = context; mIconProvider = new IconProvider(context); - mMaxAnimatableIconDuration = maxAnimatableIconDuration; mAppRevealDuration = appRevealAnimDuration; mIconExitDuration = iconExitAnimDuration; mTransactionPool = pool; @@ -122,11 +121,7 @@ public class SplashscreenContentDrawer { context, splashScreenResId); if (contentView == null) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView"); - if (emptyView) { - contentView = makeEmptySplashScreenContentView(context); - } else { - contentView = makeSplashScreenContentView(context, info); - } + contentView = makeSplashScreenContentView(context, info, emptyView); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } catch (RuntimeException e) { @@ -141,6 +136,8 @@ public class SplashscreenContentDrawer { private void updateDensity() { mIconSize = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.starting_surface_icon_size); + mDefaultIconSize = mContext.getResources().getDimensionPixelSize( + com.android.wm.shell.R.dimen.default_icon_size); mBrandingImageWidth = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.starting_surface_brand_image_width); mBrandingImageHeight = mContext.getResources().getDimensionPixelSize( @@ -195,46 +192,20 @@ public class SplashscreenContentDrawer { } } - private SplashScreenView makeEmptySplashScreenContentView(Context context) { - getWindowAttrs(context, mTmpAttrs); - final StartingWindowViewBuilder builder = new StartingWindowViewBuilder(); - final int themeBGColor = peekWindowBGColor(context); - final SplashScreenView view = builder - .setContext(context) - .setWindowBGColor(themeBGColor) - .build(); - view.setNotCopyable(); - return view; - } - - private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai) { + private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai, + boolean emptyView) { updateDensity(); getWindowAttrs(context, mTmpAttrs); final StartingWindowViewBuilder builder = new StartingWindowViewBuilder(); - final int animationDuration; - Drawable iconDrawable; - if (mTmpAttrs.mReplaceIcon != null) { - iconDrawable = mTmpAttrs.mReplaceIcon; - animationDuration = Math.max(0, - Math.min(mTmpAttrs.mAnimationDuration, mMaxAnimatableIconDuration)); - } else { - iconDrawable = mIconProvider.getIconForUI( - ai, getUserHandleForUid(ai.applicationInfo.uid)); - if (iconDrawable == null) { - iconDrawable = context.getPackageManager().getDefaultActivityIcon(); - } - animationDuration = 0; - } final int themeBGColor = peekWindowBGColor(context); // TODO (b/173975965) Tracking the performance on improved splash screen. return builder .setContext(context) .setWindowBGColor(themeBGColor) - .setIconDrawable(iconDrawable) - .setIconAnimationDuration(animationDuration) - .setBrandingDrawable(mTmpAttrs.mBrandingImage) - .setIconBackground(mTmpAttrs.mIconBgColor).build(); + .makeEmptyView(emptyView) + .setActivityInfo(ai) + .build(); } private static void getWindowAttrs(Context context, SplashScreenWindowAttrs attrs) { @@ -270,11 +241,9 @@ public class SplashscreenContentDrawer { } private class StartingWindowViewBuilder { - private Drawable mIconDrawable; - private int mIconAnimationDuration; + private ActivityInfo mActivityInfo; private Context mContext; - private Drawable mBrandingDrawable; - private @ColorInt int mIconBackground; + private boolean mEmptyView; // result private boolean mBuildComplete = false; @@ -289,26 +258,14 @@ public class SplashscreenContentDrawer { return this; } - StartingWindowViewBuilder setIconDrawable(Drawable iconDrawable) { - mIconDrawable = iconDrawable; + StartingWindowViewBuilder makeEmptyView(boolean empty) { + mEmptyView = empty; mBuildComplete = false; return this; } - StartingWindowViewBuilder setIconAnimationDuration(int iconAnimationDuration) { - mIconAnimationDuration = iconAnimationDuration; - mBuildComplete = false; - return this; - } - - StartingWindowViewBuilder setBrandingDrawable(Drawable branding) { - mBrandingDrawable = branding; - mBuildComplete = false; - return this; - } - - StartingWindowViewBuilder setIconBackground(int color) { - mIconBackground = color; + StartingWindowViewBuilder setActivityInfo(ActivityInfo ai) { + mActivityInfo = ai; mBuildComplete = false; return this; } @@ -323,40 +280,66 @@ public class SplashscreenContentDrawer { if (mBuildComplete) { return mCachedResult; } - if (mContext == null) { + if (mContext == null || mActivityInfo == null) { Slog.e(TAG, "Unable to create StartingWindowView, lack of materials!"); return null; } - if (!processAdaptiveIcon() && mIconDrawable != null) { - if (DEBUG) { - Slog.d(TAG, "The icon is not an AdaptiveIconDrawable"); + Drawable iconDrawable; + final int animationDuration; + final int iconSize; + if (mEmptyView) { + // empty splash screen case + animationDuration = 0; + iconSize = 0; + } else if (mTmpAttrs.mReplaceIcon != null) { + // replaced icon, don't process + iconDrawable = mTmpAttrs.mReplaceIcon; + animationDuration = mTmpAttrs.mAnimationDuration; + createIconDrawable(iconDrawable, mIconSize); + iconSize = mIconSize; + } else { + final float iconScale = (float) mIconSize / (float) mDefaultIconSize; + iconDrawable = mIconProvider.getIcon(mActivityInfo); + if (iconDrawable == null) { + iconDrawable = mContext.getPackageManager().getDefaultActivityIcon(); } - createIconDrawable(mIconDrawable, mIconSize); + if (!processAdaptiveIcon(iconDrawable, iconScale)) { + if (DEBUG) { + Slog.d(TAG, "The icon is not an AdaptiveIconDrawable"); + } + // TODO process legacy icon(bitmap) + final Drawable tempIcon = loadIconByDensity(iconDrawable, iconScale); + createIconDrawable(tempIcon, mIconSize); + } + animationDuration = 0; + iconSize = (int) (0.5 + mIconSize * mScale); } - final int iconSize = mFinalIconDrawable != null ? (int) (mIconSize * mScale) : 0; - mCachedResult = fillViewWithIcon(mContext, iconSize, mFinalIconDrawable); + + mCachedResult = fillViewWithIcon(iconSize, mFinalIconDrawable, animationDuration); mBuildComplete = true; return mCachedResult; } private void createIconDrawable(Drawable iconDrawable, int iconSize) { mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable( - mIconBackground != Color.TRANSPARENT ? mIconBackground : mThemeColor, + mTmpAttrs.mIconBgColor != Color.TRANSPARENT + ? mTmpAttrs.mIconBgColor : mThemeColor, iconDrawable, iconSize, mSplashscreenWorkerHandler); } - private boolean processAdaptiveIcon() { - if (!(mIconDrawable instanceof AdaptiveIconDrawable)) { + private boolean processAdaptiveIcon(Drawable iconDrawable, float iconScale) { + if (!(iconDrawable instanceof AdaptiveIconDrawable)) { return false; } Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "processAdaptiveIcon"); - final AdaptiveIconDrawable adaptiveIconDrawable = (AdaptiveIconDrawable) mIconDrawable; + final AdaptiveIconDrawable adaptiveIconDrawable = + (AdaptiveIconDrawable) iconDrawable; final DrawableColorTester backIconTester = new DrawableColorTester(adaptiveIconDrawable.getBackground()); - final Drawable iconForeground = adaptiveIconDrawable.getForeground(); + Drawable iconForeground = adaptiveIconDrawable.getForeground(); final DrawableColorTester foreIconTester = new DrawableColorTester(iconForeground, true /* filterTransparent */); @@ -382,7 +365,9 @@ public class SplashscreenContentDrawer { // B. The background of the adaptive icon is similar to the theme color, or // C. The background of the adaptive icon is grayscale, and the foreground of the // adaptive icon forms a certain contrast with the theme color. - if (!backComplex && (isRgbSimilarInHsv(mThemeColor, backMainColor) + // D. Didn't specify icon background color. + if (!backComplex && mTmpAttrs.mIconBgColor == Color.TRANSPARENT + && (isRgbSimilarInHsv(mThemeColor, backMainColor) || (backIconTester.isGrayscale() && !isRgbSimilarInHsv(mThemeColor, foreMainColor)))) { if (DEBUG) { @@ -390,8 +375,13 @@ public class SplashscreenContentDrawer { } // Reference AdaptiveIcon description, outer is 108 and inner is 72, so we // should enlarge the size 108/72 if we only draw adaptiveIcon's foreground. - if (foreIconTester.nonTransparentRatio() < ENLARGE_FOREGROUND_ICON_THRESHOLD) { - mScale = 1.5f; + final float noBgScale = + foreIconTester.nonTransparentRatio() < ENLARGE_FOREGROUND_ICON_THRESHOLD + ? NO_BACKGROUND_SCALE : 1f; + final Drawable tempIcon = loadIconByDensity(iconDrawable, iconScale * noBgScale); + if (tempIcon instanceof AdaptiveIconDrawable) { + mScale = noBgScale; + iconForeground = ((AdaptiveIconDrawable) tempIcon).getForeground(); } // Using AdaptiveIconDrawable here can help keep the shape consistent with the // current settings. @@ -401,30 +391,44 @@ public class SplashscreenContentDrawer { if (DEBUG) { Slog.d(TAG, "makeSplashScreenContentView: draw whole icon"); } - createIconDrawable(adaptiveIconDrawable, mIconSize); + final Drawable tempIcon = loadIconByDensity(iconDrawable, iconScale); + createIconDrawable(tempIcon, mIconSize); } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return true; } - private SplashScreenView fillViewWithIcon(Context context, - int iconSize, Drawable iconDrawable) { + private Drawable loadIconByDensity(Drawable baseDrawable, float scale) { + if (scale == 1 && baseDrawable != null) { + return baseDrawable; + } + final int densityDpi = mContext.getResources().getDisplayMetrics().densityDpi; + final int updateDpi = (int) (0.5f + scale * densityDpi); + return mIconProvider.getIcon(mActivityInfo, updateDpi); + } + + private SplashScreenView fillViewWithIcon(int iconSize, Drawable iconDrawable, + int animationDuration) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon"); - final SplashScreenView.Builder builder = new SplashScreenView.Builder(context); - builder.setIconSize(iconSize).setBackgroundColor(mThemeColor) - .setIconBackground(mIconBackground); + final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext); + builder.setBackgroundColor(mThemeColor); if (iconDrawable != null) { - builder.setCenterViewDrawable(iconDrawable); + builder.setIconSize(iconSize) + .setIconBackground(mTmpAttrs.mIconBgColor) + .setCenterViewDrawable(iconDrawable) + .setAnimationDurationMillis(animationDuration); } - builder.setAnimationDurationMillis(mIconAnimationDuration); - if (mBrandingDrawable != null) { - builder.setBrandingDrawable(mBrandingDrawable, mBrandingImageWidth, + if (mTmpAttrs.mBrandingImage != null) { + builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth, mBrandingImageHeight); } final SplashScreenView splashScreenView = builder.build(); if (DEBUG) { Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView); } + if (mEmptyView) { + splashScreenView.setNotCopyable(); + } splashScreenView.makeSystemUIColorsTransparent(); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return splashScreenView; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java index 85845d0d9c89..6cbba9f13586 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java @@ -59,6 +59,7 @@ public class SplashscreenIconDrawableFactory { return new ImmobileIconDrawable((AdaptiveIconDrawable) foregroundDrawable, iconSize, splashscreenWorkerHandler); } else { + // TODO for legacy icon don't use adaptive icon drawable to wrapper it return new ImmobileIconDrawable(new AdaptiveIconDrawable( new ColorDrawable(backgroundColor), foregroundDrawable), iconSize, splashscreenWorkerHandler); 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 e4b28696bc4f..6d3eeae43a96 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 @@ -114,14 +114,12 @@ public class StartingSurfaceDrawer { mContext = context; mDisplayManager = mContext.getSystemService(DisplayManager.class); mSplashScreenExecutor = splashScreenExecutor; - final int maxAnimatableIconDuration = context.getResources().getInteger( - com.android.wm.shell.R.integer.max_starting_window_intro_icon_anim_duration); final int iconExitAnimDuration = context.getResources().getInteger( com.android.wm.shell.R.integer.starting_window_icon_exit_anim_duration); final int appRevealAnimDuration = context.getResources().getInteger( com.android.wm.shell.R.integer.starting_window_app_reveal_anim_duration); - mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, - maxAnimatableIconDuration, iconExitAnimDuration, appRevealAnimDuration, pool); + mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconExitAnimDuration, + appRevealAnimDuration, pool); mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance()); } 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 index e3362870cdf0..cb7afc77a65b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java @@ -15,18 +15,10 @@ */ package com.android.wm.shell.startingsurface; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; -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_SAME_PACKAGE; -import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; @@ -68,27 +60,24 @@ import java.util.function.BiConsumer; */ public class StartingWindowController implements RemoteCallable<StartingWindowController> { private static final String TAG = StartingWindowController.class.getSimpleName(); + // TODO b/183150443 Keep this flag open for a while, several things might need to adjust. - static final boolean DEBUG_SPLASH_SCREEN = true; - static final boolean DEBUG_TASK_SNAPSHOT = false; + public static final boolean DEBUG_SPLASH_SCREEN = true; + public static final boolean DEBUG_TASK_SNAPSHOT = false; private final StartingSurfaceDrawer mStartingSurfaceDrawer; - private final StartingTypeChecker mStartingTypeChecker = new StartingTypeChecker(); + private final StartingWindowTypeAlgorithm mStartingWindowTypeAlgorithm; private BiConsumer<Integer, Integer> mTaskLaunchingCallback; private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl(); private final Context mContext; private final ShellExecutor mSplashScreenExecutor; - // For Car Launcher - public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) { - this(context, splashScreenExecutor, new TransactionPool()); - } - public StartingWindowController(Context context, ShellExecutor splashScreenExecutor, - TransactionPool pool) { + StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, TransactionPool pool) { mContext = context; mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool); + mStartingWindowTypeAlgorithm = startingWindowTypeAlgorithm; mSplashScreenExecutor = splashScreenExecutor; } @@ -109,90 +98,6 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo return mSplashScreenExecutor; } - private static class StartingTypeChecker { - - private @StartingWindowInfo.StartingWindowType int - estimateStartingWindowType(StartingWindowInfo windowInfo) { - 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; - final boolean samePackage = (parameter & TYPE_PARAMETER_SAME_PACKAGE) != 0; - return estimateStartingWindowType(windowInfo, newTask, taskSwitch, - processRunning, allowTaskSnapshot, activityCreated, samePackage); - } - - // reference from ActivityRecord#getStartingWindowType - private int estimateStartingWindowType(StartingWindowInfo windowInfo, - boolean newTask, boolean taskSwitch, boolean processRunning, - boolean allowTaskSnapshot, boolean activityCreated, boolean samePackage) { - if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { - Slog.d(TAG, "preferredStartingWindowType newTask " + newTask - + " taskSwitch " + taskSwitch - + " processRunning " + processRunning - + " allowTaskSnapshot " + allowTaskSnapshot - + " activityCreated " + activityCreated - + " samePackage " + samePackage); - } - if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) { - if (!processRunning) { - return STARTING_WINDOW_TYPE_SPLASH_SCREEN; - } - if (newTask) { - if (samePackage) { - return STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; - } else { - return STARTING_WINDOW_TYPE_SPLASH_SCREEN; - } - } - if (taskSwitch && !activityCreated) { - return STARTING_WINDOW_TYPE_SPLASH_SCREEN; - } - } - if (taskSwitch && allowTaskSnapshot) { - final TaskSnapshot snapshot = windowInfo.mTaskSnapshot; - 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; - } - if (!snapshot.getTopActivityComponent().equals(windowInfo.taskInfo.topActivity)) { - if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { - Slog.d(TAG, "isSnapshotCompatible obsoleted snapshot " - + windowInfo.taskInfo.topActivity); - } - 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; - } - } - /* * Registers the starting window listener. * @@ -212,7 +117,8 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) { mSplashScreenExecutor.execute(() -> { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addStartingWindow"); - final int suggestionType = mStartingTypeChecker.estimateStartingWindowType( + + final int suggestionType = mStartingWindowTypeAlgorithm.getSuggestedWindowType( windowInfo); final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo; if (mTaskLaunchingCallback != null && shouldSendToListener(suggestionType)) { @@ -228,8 +134,10 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo final TaskSnapshot snapshot = windowInfo.mTaskSnapshot; mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot); + } else /* suggestionType == STARTING_WINDOW_TYPE_NONE */ { + // Don't add a staring window. } - // If prefer don't show, then don't show! + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); }); } diff --git a/core/java/android/net/TunnelConnectionParams.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowTypeAlgorithm.java index f5b35395b0bf..de221ed4cea7 100644 --- a/core/java/android/net/TunnelConnectionParams.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowTypeAlgorithm.java @@ -13,17 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.net; + +package com.android.wm.shell.startingsurface; + +import android.window.StartingWindowInfo; /** - * TunnelConnectionParams represents a configuration to set up a tunnel connection. - * - * <p>Concrete implementations for a control plane protocol should implement this interface. - * Subclasses should be immutable data classes containing connection, authentication and - * authorization parameters required to establish a tunnel connection. - * - * @see android.net.ipsec.ike.IkeTunnelConnectionParams + * Used by {@link StartingWindowController} for determining the type of a new starting window. */ -// TODO:b/186071626 Remove TunnelConnectionParams when non-updatable API stub can resolve -// IkeTunnelConnectionParams -public interface TunnelConnectionParams {} +public interface StartingWindowTypeAlgorithm { + /** + * @return suggested type for the given window. + */ + @StartingWindowInfo.StartingWindowType + int getSuggestedWindowType(StartingWindowInfo windowInfo); +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java new file mode 100644 index 000000000000..9948e7d1f9c4 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.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.wm.shell.startingsurface.phone; + +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; +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_SAME_PACKAGE; +import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; + +import static com.android.wm.shell.startingsurface.StartingWindowController.DEBUG_SPLASH_SCREEN; +import static com.android.wm.shell.startingsurface.StartingWindowController.DEBUG_TASK_SNAPSHOT; + +import android.util.Slog; +import android.window.StartingWindowInfo; +import android.window.TaskSnapshot; + +import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; + +/** + * Algorithm for determining the type of a new starting window on handheld devices. + * At the moment also used on Android Auto. + */ +public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgorithm { + private static final String TAG = PhoneStartingWindowTypeAlgorithm.class.getSimpleName(); + + @Override + public int getSuggestedWindowType(StartingWindowInfo windowInfo) { + 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; + final boolean samePackage = (parameter & TYPE_PARAMETER_SAME_PACKAGE) != 0; + final boolean topIsHome = windowInfo.taskInfo.topActivityType == ACTIVITY_TYPE_HOME; + + if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { + Slog.d(TAG, "preferredStartingWindowType newTask " + newTask + + " taskSwitch " + taskSwitch + + " processRunning " + processRunning + + " allowTaskSnapshot " + allowTaskSnapshot + + " activityCreated " + activityCreated + + " samePackage " + samePackage + + " topIsHome " + topIsHome); + } + if (!topIsHome) { + if (!processRunning) { + return STARTING_WINDOW_TYPE_SPLASH_SCREEN; + } + if (newTask) { + if (samePackage) { + return STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; + } else { + return STARTING_WINDOW_TYPE_SPLASH_SCREEN; + } + } + if (taskSwitch && !activityCreated) { + return STARTING_WINDOW_TYPE_SPLASH_SCREEN; + } + } + if (taskSwitch && allowTaskSnapshot) { + if (isSnapshotCompatible(windowInfo)) { + return STARTING_WINDOW_TYPE_SNAPSHOT; + } + if (!topIsHome) { + 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) { + final TaskSnapshot snapshot = windowInfo.mTaskSnapshot; + if (snapshot == null) { + if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { + Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId); + } + return false; + } + if (!snapshot.getTopActivityComponent().equals(windowInfo.taskInfo.topActivity)) { + if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { + Slog.d(TAG, "isSnapshotCompatible obsoleted snapshot " + + windowInfo.taskInfo.topActivity); + } + 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; + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/tv/TvStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/tv/TvStartingWindowTypeAlgorithm.java new file mode 100644 index 000000000000..6e7dec590308 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/tv/TvStartingWindowTypeAlgorithm.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.startingsurface.tv; + +import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; + +import android.window.StartingWindowInfo; + +import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; + +/** + * Algorithm for determining the type of a new starting window on Android TV. + * For now we always show empty splash screens on Android TV. + */ +public class TvStartingWindowTypeAlgorithm implements StartingWindowTypeAlgorithm { + @Override + public int getSuggestedWindowType(StartingWindowInfo windowInfo) { + // For now we want to always show empty splash screens on TV. + return STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt index 134d00be73e8..741773e8f61a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt @@ -22,6 +22,7 @@ import android.platform.test.annotations.Presubmit import android.system.helpers.ActivityHelper import android.util.Log import android.view.Surface +import androidx.test.filters.FlakyTest import androidx.test.platform.app.InstrumentationRegistry import com.android.compatibility.common.util.SystemUtil import com.android.server.wm.flicker.FlickerBuilderProvider @@ -138,7 +139,7 @@ abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter) append("$primaryApp $secondaryApp") } - @Presubmit + @FlakyTest(bugId = 186510496) @Test open fun navBarLayerIsAlwaysVisible() { testSpec.navBarLayerIsAlwaysVisible() diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt index 6bc9a5c5982c..04f97c8a4c99 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt @@ -16,7 +16,7 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.Presubmit import android.provider.Settings import android.view.Surface import androidx.test.filters.RequiresDevice @@ -25,7 +25,6 @@ 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.helpers.canSplitScreen -import com.android.server.wm.flicker.helpers.openQuickstep import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import com.android.wm.shell.flicker.dockedStackDividerIsInvisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper @@ -45,7 +44,6 @@ import org.junit.runners.Parameterized * * To run this test: `atest WMShellFlickerTests:EnterSplitScreenNotSupportNonResizable` */ -@Postsubmit @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @@ -64,7 +62,6 @@ class EnterSplitScreenNotSupportNonResizable( } } transitions { - device.openQuickstep(wmHelper) if (device.canSplitScreen(wmHelper)) { Assert.fail("Non-resizeable app should not enter split screen") } @@ -96,6 +93,7 @@ class EnterSplitScreenNotSupportNonResizable( prevSupportNonResizableInMultiWindow) } + @Presubmit @Test fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible() diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt index 91ca7c1d2a72..2832bb4d15d4 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt @@ -16,7 +16,7 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.Presubmit import android.provider.Settings import android.view.Surface import androidx.test.filters.RequiresDevice @@ -43,7 +43,6 @@ import org.junit.runners.Parameterized * * To run this test: `atest WMShellFlickerTests:EnterSplitScreenSupportNonResizable` */ -@Postsubmit @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @@ -91,9 +90,11 @@ class EnterSplitScreenSupportNonResizable( prevSupportNonResizableInMultiWindow) } + @Presubmit @Test fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible() + @Presubmit @Test fun appWindowIsVisible() { testSpec.assertWmEnd { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt index 968aff1ce572..32afd190af2b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt @@ -16,7 +16,7 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.Presubmit import android.provider.Settings import android.view.Surface import androidx.test.filters.RequiresDevice @@ -46,7 +46,6 @@ import org.junit.runners.Parameterized * support non-resizable in multi window, it should trigger exit split screen. * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentNotSupportNonResizable` */ -@Postsubmit @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @@ -95,25 +94,31 @@ class LegacySplitScreenFromIntentNotSupportNonResizable( prevSupportNonResizableInMultiWindow) } + @Presubmit @Test fun resizableAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName) + @Presubmit @Test fun nonResizableAppLayerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName) + @Presubmit @Test fun resizableAppWindowBecomesInvisible() = testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName) + @Presubmit @Test fun nonResizableAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName) + @Presubmit @Test fun dockedStackDividerIsInvisibleAtEnd() = testSpec.dockedStackDividerIsInvisible() + @Presubmit @Test fun onlyNonResizableAppWindowIsVisibleAtEnd() { testSpec.assertWmEnd { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt index 8d206730b436..af307580df3f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt @@ -16,7 +16,7 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.Presubmit import android.provider.Settings import android.view.Surface import androidx.test.filters.RequiresDevice @@ -44,7 +44,6 @@ import org.junit.runners.Parameterized * non-resizable in multi window, it should show the non-resizable app in split screen. * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentSupportNonResizable` */ -@Postsubmit @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @@ -93,17 +92,21 @@ class LegacySplitScreenFromIntentSupportNonResizable( prevSupportNonResizableInMultiWindow) } + @Presubmit @Test fun nonResizableAppLayerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName) + @Presubmit @Test fun nonResizableAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName) + @Presubmit @Test fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisible() + @Presubmit @Test fun bothAppsWindowsAreVisibleAtEnd() { testSpec.assertWmEnd { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt index 4e291d9ef9f0..8c6275821b97 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt @@ -16,7 +16,7 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.Presubmit import android.provider.Settings import android.view.Surface import androidx.test.filters.RequiresDevice @@ -47,7 +47,6 @@ import org.junit.runners.Parameterized * not support non-resizable in multi window, it should trigger exit split screen. * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentNotSupportNonResizable` */ -@Postsubmit @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @@ -96,25 +95,31 @@ class LegacySplitScreenFromRecentNotSupportNonResizable( prevSupportNonResizableInMultiWindow) } + @Presubmit @Test fun resizableAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName) + @Presubmit @Test fun nonResizableAppLayerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName) + @Presubmit @Test fun resizableAppWindowBecomesInvisible() = testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName) + @Presubmit @Test fun nonResizableAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName) + @Presubmit @Test fun dockedStackDividerIsInvisibleAtEnd() = testSpec.dockedStackDividerIsInvisible() + @Presubmit @Test fun onlyNonResizableAppWindowIsVisibleAtEnd() { testSpec.assertWmEnd { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt index 880dc5567d8a..5b48f8a1df1d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt @@ -16,7 +16,7 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.Presubmit import android.provider.Settings import android.view.Surface import androidx.test.filters.RequiresDevice @@ -45,7 +45,6 @@ import org.junit.runners.Parameterized * supports non-resizable in multi window, it should show the non-resizable app in split screen. * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentSupportNonResizable` */ -@Postsubmit @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @@ -94,17 +93,21 @@ class LegacySplitScreenFromRecentSupportNonResizable( prevSupportNonResizableInMultiWindow) } + @Presubmit @Test fun nonResizableAppLayerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName) + @Presubmit @Test fun nonResizableAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName) + @Presubmit @Test fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisible() + @Presubmit @Test fun bothAppsWindowsAreVisibleAtEnd() { testSpec.assertWmEnd { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt index a7e1d0fdf90c..95672f439275 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt @@ -65,7 +65,7 @@ class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { @Test fun pipLayerBecomesVisible() { testSpec.assertLayers { - this.isVisible(pipApp.launcherName) + this.isVisible(pipApp.windowName) } } @@ -73,9 +73,11 @@ class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { @Test fun pipWindowBecomesVisible() { testSpec.assertWm { - invoke("pipWindowIsNotVisible") { !it.wmState.hasPipWindow() } - .then() - .invoke("pipWindowIsVisible") { it.wmState.hasPipWindow() } + invoke("pipWindowIsNotVisible") { + verify("Has no pip window").that(it.wmState.hasPipWindow()).isTrue() + }.then().invoke("pipWindowIsVisible") { + verify("Has pip window").that(it.wmState.hasPipWindow()).isTrue() + } } } 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 0d686f514116..fb7dac35a60a 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 @@ -71,7 +71,7 @@ class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) } } - @Presubmit + @FlakyTest(bugId = 185400889) @Test override fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, testSpec.config.endRotation, allStates = false) @@ -88,7 +88,7 @@ class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, testSpec.config.endRotation) - @Presubmit + @FlakyTest(bugId = 185400889) @Test fun appLayerRotates_StartingBounds() { testSpec.assertLayersStart { @@ -97,7 +97,7 @@ class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) } } - @Presubmit + @FlakyTest(bugId = 185400889) @Test fun appLayerRotates_EndingBounds() { testSpec.assertLayersEnd { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java index b0de02922f74..2b5cd601b200 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java @@ -69,6 +69,7 @@ public final class TestRunningTaskInfoBuilder { info.configuration.windowConfiguration.setActivityType(mActivityType); info.token = mToken; info.isResizeable = true; + info.supportsMultiWindow = true; return info; } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java index 9a80a5545984..2bb7204c7941 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java @@ -19,6 +19,8 @@ package com.android.wm.shell.bubbles; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static junit.framework.TestCase.assertEquals; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; @@ -799,6 +801,15 @@ public class BubbleDataTest extends ShellTestCase { assertExpandedChangedTo(false); } + @Test + public void test_addToOverflow_doesntAllowDupes() { + assertEquals(0, mBubbleData.getOverflowBubbles().size()); + mBubbleData.overflowBubble(Bubbles.DISMISS_AGED, mBubbleA1); + mBubbleData.overflowBubble(Bubbles.DISMISS_AGED, mBubbleA1); + mBubbleData.overflowBubble(Bubbles.DISMISS_AGED, mBubbleA1); + assertEquals(1, mBubbleData.getOverflowBubbles().size()); + } + private void verifyUpdateReceived() { verify(mListener).applyUpdate(mUpdateCaptor.capture()); reset(mListener); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java index 63b94139dd9c..882d38286130 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java @@ -18,6 +18,7 @@ package com.android.wm.shell.pip; import static android.util.RotationUtils.rotateBounds; import static android.view.Surface.ROTATION_0; +import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP; @@ -133,17 +134,30 @@ public class PipAnimationControllerTest extends ShellTestCase { @Test public void pipTransitionAnimator_rotatedEndValue() { + final DummySurfaceControlTx tx = new DummySurfaceControlTx(); final Rect startBounds = new Rect(200, 700, 400, 800); final Rect endBounds = new Rect(0, 0, 500, 1000); - final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController + // Fullscreen to PiP. + PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController .getAnimator(mTaskInfo, mLeash, null, startBounds, endBounds, null, - TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_90); + TRANSITION_DIRECTION_LEAVE_PIP, 0, ROTATION_90); // Apply fraction 1 to compute the end value. - animator.applySurfaceControlTransaction(mLeash, new DummySurfaceControlTx(), 1); + animator.applySurfaceControlTransaction(mLeash, tx, 1); final Rect rotatedEndBounds = new Rect(endBounds); rotateBounds(rotatedEndBounds, endBounds, ROTATION_90); assertEquals("Expect 90 degree rotated bounds", rotatedEndBounds, animator.mCurrentValue); + + // PiP to fullscreen. + startBounds.set(0, 0, 1000, 500); + endBounds.set(200, 100, 400, 500); + animator = mPipAnimationController.getAnimator(mTaskInfo, mLeash, startBounds, startBounds, + endBounds, null, TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_270); + animator.applySurfaceControlTransaction(mLeash, tx, 1); + rotatedEndBounds.set(endBounds); + rotateBounds(rotatedEndBounds, startBounds, ROTATION_270); + + assertEquals("Expect 270 degree rotated bounds", rotatedEndBounds, animator.mCurrentValue); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipSnapAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipSnapAlgorithmTest.java index dcee2e1847b2..b9226d2b9b91 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipSnapAlgorithmTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipSnapAlgorithmTest.java @@ -38,6 +38,8 @@ public class PipSnapAlgorithmTest extends ShellTestCase { private static final int DEFAULT_STASH_OFFSET = 32; private static final Rect DISPLAY_BOUNDS = new Rect(0, 0, 2000, 2000); private static final Rect STACK_BOUNDS_CENTERED = new Rect(900, 900, 1100, 1100); + private static final Rect INSET_BOUNDS_EMPTY = new Rect(0, 0, 0, 0); + private static final Rect INSET_BOUNDS_RIGHT = new Rect(0, 0, 200, 0); private static final Rect MOVEMENT_BOUNDS = new Rect(0, 0, DISPLAY_BOUNDS.width() - STACK_BOUNDS_CENTERED.width(), DISPLAY_BOUNDS.width() - STACK_BOUNDS_CENTERED.width()); @@ -99,7 +101,8 @@ public class PipSnapAlgorithmTest extends ShellTestCase { final Rect bounds = new Rect(STACK_BOUNDS_CENTERED); mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, snapFraction, - PipBoundsState.STASH_TYPE_NONE, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS); + PipBoundsState.STASH_TYPE_NONE, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS, + INSET_BOUNDS_EMPTY); assertEquals(MOVEMENT_BOUNDS.right, bounds.left); assertEquals(MOVEMENT_BOUNDS.bottom, bounds.top); @@ -111,7 +114,8 @@ public class PipSnapAlgorithmTest extends ShellTestCase { final Rect bounds = new Rect(STACK_BOUNDS_CENTERED); mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, snapFraction, - PipBoundsState.STASH_TYPE_LEFT, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS); + PipBoundsState.STASH_TYPE_LEFT, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS, + INSET_BOUNDS_EMPTY); final int offBoundsWidth = bounds.width() - DEFAULT_STASH_OFFSET; assertEquals(MOVEMENT_BOUNDS.left - offBoundsWidth, bounds.left); @@ -124,13 +128,28 @@ public class PipSnapAlgorithmTest extends ShellTestCase { final Rect bounds = new Rect(STACK_BOUNDS_CENTERED); mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, snapFraction, - PipBoundsState.STASH_TYPE_RIGHT, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS); + PipBoundsState.STASH_TYPE_RIGHT, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS, + INSET_BOUNDS_EMPTY); assertEquals(DISPLAY_BOUNDS.right - DEFAULT_STASH_OFFSET, bounds.left); assertEquals(MOVEMENT_BOUNDS.bottom, bounds.top); } @Test + public void testApplySnapFraction_stashedRight_withInset() { + final float snapFraction = 2f; + final Rect bounds = new Rect(STACK_BOUNDS_CENTERED); + + mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, snapFraction, + PipBoundsState.STASH_TYPE_RIGHT, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS, + INSET_BOUNDS_RIGHT); + + assertEquals(DISPLAY_BOUNDS.right - DEFAULT_STASH_OFFSET - INSET_BOUNDS_RIGHT.right, + bounds.left); + assertEquals(MOVEMENT_BOUNDS.bottom, bounds.top); + } + + @Test public void testSnapRectToClosestEdge_rightEdge() { final Rect bounds = new Rect(STACK_BOUNDS_CENTERED); // Move the centered rect slightly to the right side. @@ -183,7 +202,8 @@ public class PipSnapAlgorithmTest extends ShellTestCase { final Rect bounds = new Rect(STACK_BOUNDS_CENTERED); // Stash it on the left side. mPipSnapAlgorithm.applySnapFraction(bounds, MOVEMENT_BOUNDS, 3.5f, - PipBoundsState.STASH_TYPE_LEFT, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS); + PipBoundsState.STASH_TYPE_LEFT, DEFAULT_STASH_OFFSET, DISPLAY_BOUNDS, + INSET_BOUNDS_EMPTY); mPipSnapAlgorithm.snapRectToClosestEdge(bounds, MOVEMENT_BOUNDS, bounds, PipBoundsState.STASH_TYPE_LEFT); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java new file mode 100644 index 000000000000..dd10aa7752f5 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java @@ -0,0 +1,224 @@ +/* + * 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.pip.phone; + +import static junit.framework.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.graphics.Rect; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.MotionEvent; + +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.common.FloatingContentCoordinator; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.pip.PipBoundsAlgorithm; +import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipSnapAlgorithm; +import com.android.wm.shell.pip.PipTaskOrganizer; +import com.android.wm.shell.pip.PipTransitionController; +import com.android.wm.shell.pip.PipUiEventLogger; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Unit tests against {@link PipResizeGestureHandler} + */ +@RunWith(AndroidTestingRunner.class) +@SmallTest +@TestableLooper.RunWithLooper(setAsMainLooper = true) +public class PipResizeGestureHandlerTest extends ShellTestCase { + private static final int STEP_SIZE = 40; + private final MotionEvent.PointerProperties[] mPp = new MotionEvent.PointerProperties[2]; + + @Mock + private PhonePipMenuController mPhonePipMenuController; + + @Mock + private PipTaskOrganizer mPipTaskOrganizer; + + @Mock + private PipDismissTargetHandler mPipDismissTargetHandler; + + @Mock + private PipTransitionController mMockPipTransitionController; + + @Mock + private FloatingContentCoordinator mFloatingContentCoordinator; + + @Mock + private PipUiEventLogger mPipUiEventLogger; + + @Mock + private ShellExecutor mMainExecutor; + + private PipResizeGestureHandler mPipResizeGestureHandler; + + private PipBoundsState mPipBoundsState; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mPipBoundsState = new PipBoundsState(mContext); + final PipSnapAlgorithm pipSnapAlgorithm = new PipSnapAlgorithm(); + final PipBoundsAlgorithm pipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, + mPipBoundsState, pipSnapAlgorithm); + final PipMotionHelper motionHelper = new PipMotionHelper(mContext, mPipBoundsState, + mPipTaskOrganizer, mPhonePipMenuController, pipSnapAlgorithm, + mMockPipTransitionController, mFloatingContentCoordinator); + mPipResizeGestureHandler = new PipResizeGestureHandler(mContext, pipBoundsAlgorithm, + mPipBoundsState, motionHelper, mPipTaskOrganizer, mPipDismissTargetHandler, + (Rect bounds) -> new Rect(), () -> {}, mPipUiEventLogger, mPhonePipMenuController, + mMainExecutor) { + @Override + public void pilferPointers() { + // Overridden just to avoid calling into InputMonitor. + } + }; + + for (int i = 0; i < 2; i++) { + MotionEvent.PointerProperties pointerProperty = new MotionEvent.PointerProperties(); + pointerProperty.id = i; + pointerProperty.toolType = MotionEvent.TOOL_TYPE_FINGER; + mPp[i] = pointerProperty; + } + + mPipResizeGestureHandler.init(); + mPipResizeGestureHandler.onSystemUiStateChanged(true); + } + + @Test + public void twoInput_triggersPinchResize_getBigger() { + assertTrue(mPipResizeGestureHandler.isUsingPinchToZoom()); + + int topLeft = 200; + int bottomRight = 500; + mPipBoundsState.setBounds(new Rect(topLeft, topLeft, bottomRight, bottomRight)); + + // Start inside the PiP bounds first. + topLeft += STEP_SIZE; + bottomRight -= STEP_SIZE; + MotionEvent downEvent = + obtainMotionEvent(MotionEvent.ACTION_POINTER_DOWN, topLeft, bottomRight); + assertTrue(mPipResizeGestureHandler.willStartResizeGesture(downEvent)); + + // Slowly move outward. + topLeft -= STEP_SIZE; + bottomRight += STEP_SIZE; + MotionEvent moveEvent1 = obtainMotionEvent(MotionEvent.ACTION_MOVE, topLeft, bottomRight); + mPipResizeGestureHandler.onPinchResize(moveEvent1); + + // Move outward more. + topLeft -= STEP_SIZE; + bottomRight += STEP_SIZE; + MotionEvent moveEvent2 = obtainMotionEvent(MotionEvent.ACTION_MOVE, topLeft, bottomRight); + mPipResizeGestureHandler.onPinchResize(moveEvent2); + + verify(mPipTaskOrganizer, times(2)) + .scheduleUserResizePip(any(), any(), anyFloat(), any()); + + MotionEvent upEvent = obtainMotionEvent(MotionEvent.ACTION_UP, topLeft, bottomRight); + mPipResizeGestureHandler.onPinchResize(upEvent); + + verify(mPipTaskOrganizer, times(1)) + .scheduleAnimateResizePip(any(), any(), anyInt(), anyFloat(), any()); + + assertTrue("The new size should be bigger than the original PiP size.", + mPipResizeGestureHandler.getLastResizeBounds().width() + > mPipBoundsState.getBounds().width()); + } + + @Test + public void twoInput_triggersPinchResize_getSmaller() { + assertTrue(mPipResizeGestureHandler.isUsingPinchToZoom()); + + int topLeft = 200; + int bottomRight = 500; + mPipBoundsState.setBounds(new Rect(topLeft, topLeft, bottomRight, bottomRight)); + + + topLeft += STEP_SIZE; + bottomRight -= STEP_SIZE; + MotionEvent downEvent = + obtainMotionEvent(MotionEvent.ACTION_POINTER_DOWN, topLeft, bottomRight); + assertTrue(mPipResizeGestureHandler.willStartResizeGesture(downEvent)); + + topLeft += STEP_SIZE; + bottomRight -= STEP_SIZE; + MotionEvent moveEvent1 = obtainMotionEvent(MotionEvent.ACTION_MOVE, topLeft, bottomRight); + mPipResizeGestureHandler.onPinchResize(moveEvent1); + + topLeft += STEP_SIZE; + bottomRight -= STEP_SIZE; + MotionEvent moveEvent2 = obtainMotionEvent(MotionEvent.ACTION_MOVE, topLeft, bottomRight); + mPipResizeGestureHandler.onPinchResize(moveEvent2); + + verify(mPipTaskOrganizer, times(2)) + .scheduleUserResizePip(any(), any(), anyFloat(), any()); + + MotionEvent upEvent = obtainMotionEvent(MotionEvent.ACTION_UP, topLeft, bottomRight); + mPipResizeGestureHandler.onPinchResize(upEvent); + + verify(mPipTaskOrganizer, times(1)) + .scheduleAnimateResizePip(any(), any(), anyInt(), anyFloat(), any()); + + assertTrue("The new size should be smaller than the original PiP size.", + mPipResizeGestureHandler.getLastResizeBounds().width() + < mPipBoundsState.getBounds().width()); + } + + private MotionEvent obtainMotionEvent(int action, int topLeft, int bottomRight) { + final MotionEvent.PointerCoords[] pc = new MotionEvent.PointerCoords[2]; + for (int i = 0; i < 2; i++) { + MotionEvent.PointerCoords pointerCoord = new MotionEvent.PointerCoords(); + if (i == 0) { + pointerCoord.x = topLeft; + pointerCoord.y = topLeft; + } else { + pointerCoord.x = bottomRight; + pointerCoord.y = bottomRight; + } + pc[i] = pointerCoord; + } + return MotionEvent.obtain(0 /* downTime */, + System.currentTimeMillis(), + action, + 2 /* pointerCount */, + mPp, + pc, + 0 /* metaState */, + 0 /* buttonState */, + 0 /* xPrecision */, + 0 /* yPrecision */, + 0 /* deviceId */, + 0 /* edgeFlags */, + 0 /* source */, + 0 /* flags */); + } +} diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index 2a70f0d6a804..cb620cc475a9 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -70,9 +70,6 @@ struct TypeSpecBuilder { } // namespace -LoadedPackage::LoadedPackage() = default; -LoadedPackage::~LoadedPackage() = default; - // Precondition: The header passed in has already been verified, so reading any fields and trusting // the ResChunk_header is safe. static bool VerifyResTableType(incfs::map_ptr<ResTable_type> header) { diff --git a/libs/androidfw/PosixUtils.cpp b/libs/androidfw/PosixUtils.cpp index f1ab1493012a..4ec525a01da5 100644 --- a/libs/androidfw/PosixUtils.cpp +++ b/libs/androidfw/PosixUtils.cpp @@ -72,7 +72,8 @@ std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv) argv0[i] = argv[i].c_str(); } argv0[argv.size()] = nullptr; - switch (fork()) { + int pid = fork(); + switch (pid) { case -1: // error free(argv0); PLOG(ERROR) << "fork"; @@ -104,8 +105,10 @@ std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv) close(stdout[1]); close(stderr[1]); int status; - wait(&status); + waitpid(pid, &status, 0); if (!WIFEXITED(status)) { + close(stdout[0]); + close(stderr[0]); return nullptr; } std::unique_ptr<ProcResult> result(new ProcResult()); diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 119f531b8634..10666adfdceb 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -94,6 +94,7 @@ class AssetManager2 { }; AssetManager2(); + explicit AssetManager2(AssetManager2&& other) = default; // Sets/resets the underlying ApkAssets for this AssetManager. The ApkAssets // are not owned by the AssetManager, and must have a longer lifetime. diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index d9225cd812ef..3b222c556bfa 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -153,8 +153,6 @@ class LoadedPackage { static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk, package_property_t property_flags); - ~LoadedPackage(); - // Finds the entry with the specified type name and entry name. The names are in UTF-16 because // the underlying ResStringPool API expects this. For now this is acceptable, but since // the default policy in AAPT2 is to build UTF-8 string pools, this needs to change. @@ -275,7 +273,7 @@ class LoadedPackage { private: DISALLOW_COPY_AND_ASSIGN(LoadedPackage); - LoadedPackage(); + LoadedPackage() = default; ResStringPool type_string_pool_; ResStringPool key_string_pool_; diff --git a/libs/androidfw/include/androidfw/MutexGuard.h b/libs/androidfw/include/androidfw/MutexGuard.h index 64924f433245..6fc6d64e2f6e 100644 --- a/libs/androidfw/include/androidfw/MutexGuard.h +++ b/libs/androidfw/include/androidfw/MutexGuard.h @@ -18,6 +18,7 @@ #define ANDROIDFW_MUTEXGUARD_H #include <mutex> +#include <optional> #include <type_traits> #include "android-base/macros.h" @@ -47,34 +48,32 @@ class Guarded { static_assert(!std::is_pointer<T>::value, "T must not be a raw pointer"); public: - explicit Guarded() : guarded_() { + Guarded() : guarded_(std::in_place, T()) { } - template <typename U = T> - explicit Guarded(const T& guarded, - typename std::enable_if<std::is_copy_constructible<U>::value>::type = void()) - : guarded_(guarded) { + explicit Guarded(const T& guarded) : guarded_(std::in_place, guarded) { } - template <typename U = T> - explicit Guarded(T&& guarded, - typename std::enable_if<std::is_move_constructible<U>::value>::type = void()) - : guarded_(std::move(guarded)) { + explicit Guarded(T&& guarded) : guarded_(std::in_place, std::forward<T>(guarded)) { + } + + ~Guarded() { + std::lock_guard<std::mutex> scoped_lock(lock_); + guarded_.reset(); } private: friend class ScopedLock<T>; - DISALLOW_COPY_AND_ASSIGN(Guarded); std::mutex lock_; - T guarded_; + std::optional<T> guarded_; }; template <typename T> class ScopedLock { public: - explicit ScopedLock(Guarded<T>& guarded) : lock_(guarded.lock_), guarded_(guarded.guarded_) { + explicit ScopedLock(Guarded<T>& guarded) : lock_(guarded.lock_), guarded_(*guarded.guarded_) { } T& operator*() { diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp index c2642d3fdb55..6eb6e1ee4a5c 100644 --- a/libs/hwui/effects/StretchEffect.cpp +++ b/libs/hwui/effects/StretchEffect.cpp @@ -237,7 +237,7 @@ sk_sp<SkShader> StretchEffect::getShader(const sk_sp<SkImage>& snapshotImage) co } sk_sp<SkRuntimeEffect> StretchEffect::getStretchEffect() { - const static SkRuntimeEffect::Result instance = SkRuntimeEffect::Make(stretchShader); + const static SkRuntimeEffect::Result instance = SkRuntimeEffect::MakeForShader(stretchShader); return instance.effect; } diff --git a/libs/hwui/hwui/AnimatedImageThread.cpp b/libs/hwui/hwui/AnimatedImageThread.cpp index c8990039875e..3d5841d308fb 100644 --- a/libs/hwui/hwui/AnimatedImageThread.cpp +++ b/libs/hwui/hwui/AnimatedImageThread.cpp @@ -22,13 +22,16 @@ namespace android { namespace uirenderer { AnimatedImageThread& AnimatedImageThread::getInstance() { - static AnimatedImageThread* sInstance = new AnimatedImageThread(); - return *sInstance; + [[clang::no_destroy]] static sp<AnimatedImageThread> sInstance = []() { + sp<AnimatedImageThread> thread = sp<AnimatedImageThread>::make(); + thread->start("AnimatedImageThread"); + return thread; + }(); + return *sInstance.get(); } AnimatedImageThread::AnimatedImageThread() { setpriority(PRIO_PROCESS, 0, PRIORITY_NORMAL + PRIORITY_MORE_FAVORABLE); - start("AnimatedImageThread"); } std::future<AnimatedImageDrawable::Snapshot> AnimatedImageThread::decodeNextFrame( diff --git a/libs/hwui/hwui/AnimatedImageThread.h b/libs/hwui/hwui/AnimatedImageThread.h index 9e3537430d5a..fac80e5310e8 100644 --- a/libs/hwui/hwui/AnimatedImageThread.h +++ b/libs/hwui/hwui/AnimatedImageThread.h @@ -37,6 +37,7 @@ public: std::future<AnimatedImageDrawable::Snapshot> reset(const sk_sp<AnimatedImageDrawable>&); private: + friend sp<AnimatedImageThread>; AnimatedImageThread(); }; diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp index 2e4d7f62f671..90184432e8a4 100644 --- a/libs/hwui/jni/Shader.cpp +++ b/libs/hwui/jni/Shader.cpp @@ -239,7 +239,8 @@ static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr, static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) { ScopedUtfChars strSksl(env, sksl); - auto result = SkRuntimeEffect::Make(SkString(strSksl.c_str()), SkRuntimeEffect::Options{}); + auto result = SkRuntimeEffect::MakeForShader(SkString(strSksl.c_str()), + SkRuntimeEffect::Options{}); if (result.effect.get() == nullptr) { doThrowIAE(env, result.errorText.c_str()); return 0; diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java index 242d9a3627db..f4466782ac8a 100644 --- a/location/java/android/location/GnssMeasurement.java +++ b/location/java/android/location/GnssMeasurement.java @@ -1530,6 +1530,10 @@ public final class GnssMeasurement implements Parcelable { * * <p>The value does not include the inter-frequency Ionospheric bias. * + * <p>The sign of the value is defined by the following equation: + * <pre> + * corrected pseudorange = raw pseudorange - FullInterSignalBiasNanos</pre> + * * <p>The value is only available if {@link #hasFullInterSignalBiasNanos()} is {@code true}. */ public double getFullInterSignalBiasNanos() { @@ -1626,6 +1630,10 @@ public final class GnssMeasurement implements Parcelable { * type in {@link GnssClock#getReferenceConstellationTypeForIsb())</li> * </ul> * + * <p>The sign of the value is defined by the following equation: + * <pre> + * corrected pseudorange = raw pseudorange - SatelliteInterSignalBiasNanos</pre> + * * <p>The value is only available if {@link #hasSatelliteInterSignalBiasNanos()} is {@code * true}. */ diff --git a/media/java/android/media/MediaServiceManager.java b/media/java/android/media/MediaServiceManager.java index b899559d2e50..fd89c0c67e71 100644 --- a/media/java/android/media/MediaServiceManager.java +++ b/media/java/android/media/MediaServiceManager.java @@ -45,12 +45,21 @@ public class MediaServiceManager { */ public static final class ServiceRegisterer { private final String mServiceName; + private final boolean mLazyStart; /** * @hide */ - public ServiceRegisterer(String serviceName) { + public ServiceRegisterer(String serviceName, boolean lazyStart) { mServiceName = serviceName; + mLazyStart = lazyStart; + } + + /** + * @hide + */ + public ServiceRegisterer(String serviceName) { + this(serviceName, false /*lazyStart*/); } /** @@ -61,6 +70,9 @@ public class MediaServiceManager { */ @Nullable public IBinder get() { + if (mLazyStart) { + return ServiceManager.waitForService(mServiceName); + } return ServiceManager.getService(mServiceName); } } @@ -78,7 +90,7 @@ public class MediaServiceManager { */ @NonNull public ServiceRegisterer getMediaTranscodingServiceRegisterer() { - return new ServiceRegisterer(MEDIA_TRANSCODING_SERVICE); + return new ServiceRegisterer(MEDIA_TRANSCODING_SERVICE, true /*lazyStart*/); } /** diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp index c9a7e8340dda..e05dba629d7f 100644 --- a/media/jni/tuner/TunerClient.cpp +++ b/media/jni/tuner/TunerClient.cpp @@ -326,6 +326,7 @@ void TunerClient::updateTunerResources() { // TODO: update Demux, Descrambler. } +// TODO: remove after migration to Tuner Service is done. void TunerClient::updateFrontendResources() { vector<FrontendId> ids = getFrontendIds(); if (ids.size() == 0) { @@ -446,6 +447,7 @@ sp<ILnb> TunerClient::openHidlLnbByName(string name, LnbId& lnbId) { return lnb; } +// TODO: remove after migration to Tuner Service is done. vector<int> TunerClient::getLnbHandles() { vector<int> lnbHandles; if (mTuner != NULL) { @@ -612,12 +614,13 @@ FrontendInfo TunerClient::frontendInfoAidlToHidl(TunerFrontendInfo aidlFrontendI return hidlFrontendInfo; } +// TODO: remove after migration to Tuner Service is done. int TunerClient::getResourceIdFromHandle(int handle, int /*resourceType*/) { return (handle & 0x00ff0000) >> 16; } +// TODO: remove after migration to Tuner Service is done. int TunerClient::getResourceHandleFromId(int id, int resourceType) { - // TODO: build up randomly generated id to handle mapping return (resourceType & 0x000000ff) << 24 | (id << 16) | (mResourceRequestCount++ & 0xffff); diff --git a/native/android/Android.bp b/native/android/Android.bp index 24c93ce63b1e..3ee2c18a0eab 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -127,7 +127,11 @@ cc_library_shared { cc_library_shared { name: "libandroid_net", defaults: ["libandroid_defaults"], - llndk_stubs: "libandroid_net.llndk", + llndk: { + symbol_file: "libandroid_net.map.txt", + unversioned: true, + override_export_include_dirs: ["include"], + }, srcs: ["net.c"], shared_libs: ["libnetd_client"], @@ -135,13 +139,6 @@ cc_library_shared { include_dirs: ["bionic/libc/dns/include"], } -llndk_library { - name: "libandroid_net.llndk", - export_include_dirs: ["include"], - symbol_file: "libandroid_net.map.txt", - unversioned: true, -} - // Aidl library for platform compat. cc_library_shared { name: "lib-platform-compat-native-api", diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index 087837a5c70f..7540a143c2f3 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -449,7 +449,7 @@ void ASurfaceTransaction_setGeometry(ASurfaceTransaction* aSurfaceTransaction, sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); - transaction->setCrop(surfaceControl, sourceRect); + transaction->setBufferCrop(surfaceControl, sourceRect); float dsdx = (destination.right - destination.left) / static_cast<float>(sourceRect.right - sourceRect.left); diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp index 385e455e3e1f..b0c8c612036a 100644 --- a/native/graphics/jni/imagedecoder.cpp +++ b/native/graphics/jni/imagedecoder.cpp @@ -442,6 +442,15 @@ int AImageDecoder_advanceFrame(AImageDecoder* decoder) { return ANDROID_IMAGE_DECODER_BAD_PARAMETER; } + const auto colorType = imageDecoder->getOutputInfo().colorType(); + switch (colorType) { + case kN32_SkColorType: + case kRGBA_F16_SkColorType: + break; + default: + return ANDROID_IMAGE_DECODER_INVALID_STATE; + } + if (imageDecoder->advanceFrame()) { return ANDROID_IMAGE_DECODER_SUCCESS; } diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt index a8e2517a5e90..90580fa17b79 100644 --- a/packages/Connectivity/framework/api/module-lib-current.txt +++ b/packages/Connectivity/framework/api/module-lib-current.txt @@ -10,7 +10,6 @@ package android.net { method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshots(); method @Nullable public android.net.ProxyInfo getGlobalProxy(); method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange(); - method @NonNull public static String getPrivateDnsMode(@NonNull android.content.Context); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); @@ -20,7 +19,6 @@ package android.net { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network); method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean); - method public static void setPrivateDnsMode(@NonNull android.content.Context, @NonNull String); method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>); 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); @@ -40,9 +38,6 @@ package android.net { field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10 field public static final int BLOCKED_REASON_NONE = 0; // 0x0 field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8 - field public static final String PRIVATE_DNS_MODE_OFF = "off"; - field public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic"; - field public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname"; field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0 field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1 } @@ -69,6 +64,7 @@ package android.net { method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration); method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context); method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context); + method public static int getPrivateDnsMode(@NonNull android.content.Context); method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean); method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String); @@ -85,8 +81,9 @@ package android.net { method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String); method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int); method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration); - method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull String); + method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull int); method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String); + method public static void setPrivateDnsMode(@NonNull android.content.Context, int); method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean); method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2 @@ -95,6 +92,9 @@ package android.net { field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2 field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0 field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1 + field public static final int PRIVATE_DNS_MODE_OFF = 1; // 0x1 + field public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; // 0x2 + field public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; // 0x3 } public final class NetworkAgentConfig implements android.os.Parcelable { diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java index 164b984bcdc1..0c5eaa7b6bc8 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java @@ -16,8 +16,6 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE; -import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE; import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST; import static android.net.NetworkRequest.Type.LISTEN; import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST; @@ -33,7 +31,6 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.StringDef; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; @@ -41,7 +38,6 @@ import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.ConnectivityDiagnosticsManager.DataStallReport.DetectionMethod; @@ -70,7 +66,6 @@ import android.os.UserHandle; import android.provider.Settings; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Range; @@ -821,38 +816,6 @@ public class ConnectivityManager { public static final int NETID_UNSET = 0; /** - * Private DNS Mode values. - * - * The "private_dns_mode" global setting stores a String value which is - * expected to be one of the following. - */ - - /** - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final String PRIVATE_DNS_MODE_OFF = "off"; - /** - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic"; - /** - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname"; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @StringDef(value = { - PRIVATE_DNS_MODE_OFF, - PRIVATE_DNS_MODE_OPPORTUNISTIC, - PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, - }) - public @interface PrivateDnsMode {} - - /** * Flag to indicate that an app is not subject to any restrictions that could result in its * network access blocked. * @@ -5503,44 +5466,4 @@ public class ConnectivityManager { public static Range<Integer> getIpSecNetIdRange() { return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1); } - - /** - * Get private DNS mode from settings. - * - * @param context The Context to query the private DNS mode from settings. - * @return A string of private DNS mode as one of the PRIVATE_DNS_MODE_* constants. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @NonNull - @PrivateDnsMode - public static String getPrivateDnsMode(@NonNull Context context) { - final ContentResolver cr = context.getContentResolver(); - String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE); - if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE); - // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose - // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode. - if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_MODE_OPPORTUNISTIC; - return mode; - } - - /** - * Set private DNS mode to settings. - * - * @param context The {@link Context} to set the private DNS mode. - * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static void setPrivateDnsMode(@NonNull Context context, - @NonNull @PrivateDnsMode String mode) { - if (!(mode == PRIVATE_DNS_MODE_OFF - || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC - || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { - throw new IllegalArgumentException("Invalid private dns mode"); - } - Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, mode); - } } diff --git a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java index 9a00055e0079..31e1fb058187 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java @@ -19,18 +19,15 @@ package android.net; import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER; import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE; import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.content.ContentResolver; import android.content.Context; import android.net.ConnectivityManager.MultipathPreference; -import android.net.ConnectivityManager.PrivateDnsMode; import android.provider.Settings; import android.text.TextUtils; import android.util.Range; @@ -341,6 +338,37 @@ public class ConnectivitySettingsManager { public static final String MOBILE_DATA_PREFERRED_APPS = "mobile_data_preferred_apps"; /** + * One of the private DNS modes that indicates the private DNS mode is off. + */ + public static final int PRIVATE_DNS_MODE_OFF = 1; + + /** + * One of the private DNS modes that indicates the private DNS mode is automatic, which + * will try to use the current DNS as private DNS. + */ + public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; + + /** + * One of the private DNS modes that indicates the private DNS mode is strict and the + * {@link #PRIVATE_DNS_SPECIFIER} is required, which will try to use the value of + * {@link #PRIVATE_DNS_SPECIFIER} as private DNS. + */ + public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + PRIVATE_DNS_MODE_OFF, + PRIVATE_DNS_MODE_OPPORTUNISTIC, + PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, + }) + public @interface PrivateDnsMode {} + + private static final String PRIVATE_DNS_MODE_OFF_STRING = "off"; + private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING = "opportunistic"; + private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname"; + + /** * Get mobile data activity timeout from {@link Settings}. * * @param context The {@link Context} to query the setting. @@ -689,6 +717,65 @@ public class ConnectivitySettingsManager { context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */); } + private static String getPrivateDnsModeAsString(@PrivateDnsMode int mode) { + switch (mode) { + case PRIVATE_DNS_MODE_OFF: + return PRIVATE_DNS_MODE_OFF_STRING; + case PRIVATE_DNS_MODE_OPPORTUNISTIC: + return PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING; + case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: + return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING; + default: + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + } + + private static int getPrivateDnsModeAsInt(String mode) { + switch (mode) { + case "off": + return PRIVATE_DNS_MODE_OFF; + case "hostname": + return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; + case "opportunistic": + return PRIVATE_DNS_MODE_OPPORTUNISTIC; + default: + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + } + + /** + * Get private DNS mode from settings. + * + * @param context The Context to query the private DNS mode from settings. + * @return A string of private DNS mode. + */ + @PrivateDnsMode + public static int getPrivateDnsMode(@NonNull Context context) { + final ContentResolver cr = context.getContentResolver(); + String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE); + if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE); + // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose + // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode. + if (TextUtils.isEmpty(mode)) return PRIVATE_DNS_MODE_OPPORTUNISTIC; + return getPrivateDnsModeAsInt(mode); + } + + /** + * Set private DNS mode to settings. + * + * @param context The {@link Context} to set the private DNS mode. + * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants. + */ + public static void setPrivateDnsMode(@NonNull Context context, @PrivateDnsMode int mode) { + if (!(mode == PRIVATE_DNS_MODE_OFF + || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC + || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, + getPrivateDnsModeAsString(mode)); + } + /** * Get specific private dns provider name from {@link Settings}. * @@ -731,13 +818,14 @@ public class ConnectivitySettingsManager { * constants. */ public static void setPrivateDnsDefaultMode(@NonNull Context context, - @NonNull @PrivateDnsMode String mode) { + @NonNull @PrivateDnsMode int mode) { if (!(mode == PRIVATE_DNS_MODE_OFF || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { throw new IllegalArgumentException("Invalid private dns mode"); } - Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, mode); + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, + getPrivateDnsModeAsString(mode)); } /** diff --git a/packages/Connectivity/framework/src/android/net/ProxyInfo.java b/packages/Connectivity/framework/src/android/net/ProxyInfo.java index 745e20f1542e..0deda371f6b9 100644 --- a/packages/Connectivity/framework/src/android/net/ProxyInfo.java +++ b/packages/Connectivity/framework/src/android/net/ProxyInfo.java @@ -37,8 +37,9 @@ import java.util.Locale; * Apache HTTP stack. So {@link URLConnection} and Apache's {@code HttpClient} will use * them automatically. * - * Other HTTP stacks will need to obtain the proxy info from - * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}. + * Other HTTP stacks will need to obtain the proxy info by watching for the + * {@link Proxy#PROXY_CHANGE_ACTION} broadcast and calling methods such as + * {@link android.net.ConnectivityManager#getDefaultProxy}. */ public class ProxyInfo implements Parcelable { diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml index 7314005f8be5..57e74e95e90f 100644 --- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml +++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml @@ -18,7 +18,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Resurser för systemanslutning"</string> - <string name="wifi_available_sign_in" msgid="5254156478006453593">"Logga in på ett Wi-Fi-nätverk"</string> + <string name="wifi_available_sign_in" msgid="5254156478006453593">"Logga in på ett wifi-nätverk"</string> <string name="network_available_sign_in" msgid="7794369329839408792">"Logga in på nätverket"</string> <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) --> <skip /> @@ -34,7 +34,7 @@ <string name="network_switch_metered_toast" msgid="8831325515040986641">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string> <string-array name="network_switch_type_name"> <item msgid="5454013645032700715">"mobildata"</item> - <item msgid="6341719431034774569">"Wi-Fi"</item> + <item msgid="6341719431034774569">"Wifi"</item> <item msgid="5081440868800877512">"Bluetooth"</item> <item msgid="1160736166977503463">"Ethernet"</item> <item msgid="7347618872551558605">"VPN"</item> diff --git a/packages/InputDevices/res/raw/keyboard_layout_arabic.kcm b/packages/InputDevices/res/raw/keyboard_layout_arabic.kcm index 2a95cfe6f8b1..44d5a0c376f7 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_arabic.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_arabic.kcm @@ -85,14 +85,14 @@ key 8 { key 9 { label: '9' base: '\u0669' - shift: '(' + shift: ')' capslock: '9' } key 0 { label: '0' base: '\u0660' - shift: ')' + shift: '(' capslock: '0' } diff --git a/packages/PrintSpooler/res/values-my/strings.xml b/packages/PrintSpooler/res/values-my/strings.xml index cb0b89944aac..14ccbf8a8ac7 100644 --- a/packages/PrintSpooler/res/values-my/strings.xml +++ b/packages/PrintSpooler/res/values-my/strings.xml @@ -27,7 +27,7 @@ <string name="label_duplex" msgid="5370037254347072243">"နှစ်ဖက်လှ"</string> <string name="label_orientation" msgid="2853142581990496477">"အနေအထား"</string> <string name="label_pages" msgid="7768589729282182230">"စာမျက်နှာများ"</string> - <string name="destination_default_text" msgid="5422708056807065710">"ပုံနှိပ်စက်ကို ရွေးပါ"</string> + <string name="destination_default_text" msgid="5422708056807065710">"ပရင်တာကို ရွေးပါ"</string> <string name="template_all_pages" msgid="3322235982020148762">"အားလုံး <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string> <string name="template_page_range" msgid="428638530038286328">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g>ဘောင် ထဲမှာ"</string> <string name="pages_range_example" msgid="8558694453556945172">"ဥပမာ ၁-၅၊ ၈၊ ၁၁-၁၃"</string> @@ -36,7 +36,7 @@ <string name="printing_app_crashed" msgid="854477616686566398">"စာထုတ်လုပ်သော အက်ပ်ခဏ ပျက်သွားပါသည်"</string> <string name="generating_print_job" msgid="3119608742651698916">"စာထုတ်အလုပ်ကို လုပ်နေပါသည်"</string> <string name="save_as_pdf" msgid="5718454119847596853">"PDF အဖြစ်သိမ်းရန်"</string> - <string name="all_printers" msgid="5018829726861876202">"စာထုတ်စက် အားလုံး"</string> + <string name="all_printers" msgid="5018829726861876202">"ပ အားလုံး"</string> <string name="print_dialog" msgid="32628687461331979">"စာထုတ်ရန် အချက်ပြခြင်း"</string> <string name="current_page_template" msgid="5145005201131935302">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g>/<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string> <string name="page_description_template" msgid="6831239682256197161">"<xliff:g id="PAGE_COUNT">%2$d</xliff:g>ထဲက စာမျက်နှာ <xliff:g id="CURRENT_PAGE">%1$d</xliff:g>"</string> @@ -48,16 +48,16 @@ <string name="print_options_expanded" msgid="6944679157471691859">"ပရင့်ထုတ် ရွေးစရာများကို ချဲ့ထား"</string> <string name="print_options_collapsed" msgid="7455930445670414332">"ပရင့်ထုတ် ရွေးစရာများကို ခေါက်ထား"</string> <string name="search" msgid="5421724265322228497">"ရှာဖွေခြင်း"</string> - <string name="all_printers_label" msgid="3178848870161526399">"စာထုတ်စက် အားလုံး"</string> + <string name="all_printers_label" msgid="3178848870161526399">"ပ အားလုံး"</string> <string name="add_print_service_label" msgid="5356702546188981940">"ဝန်ဆောင်မှုထည့်ရန်"</string> <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"ရှာဖွေစရာ နေရာ မြင်တွေ့ရပါသည်"</string> <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"ရှာဖွေရန် နေရာ ပျောက်ကွယ်နေပါသည်"</string> <string name="print_add_printer" msgid="1088656468360653455">"ပရင်တာထည့်ရန်"</string> - <string name="print_select_printer" msgid="7388760939873368698">"စာထုတ်စက်ကို ရွေးရန်"</string> - <string name="print_forget_printer" msgid="5035287497291910766">"စာထုတ်စက်ကို မေ့လိုက်ရန်"</string> + <string name="print_select_printer" msgid="7388760939873368698">"ပရင်တာကို ရွေးရန်"</string> + <string name="print_forget_printer" msgid="5035287497291910766">"ပရင်တာကို မေ့လိုက်ရန်"</string> <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868"> - <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> စာထုတ်စက်များ တွေ့ရှိပါသည်</item> - <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>စာထုတ်စက် တွေ့ရှိပါသည်</item> + <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ပရင်တာများ တွေ့ရှိပါသည်</item> + <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>ပရင်တာ တွေ့ရှိပါသည်</item> </plurals> <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string> <string name="printer_info_desc" msgid="7181988788991581654">"ဤပရင်တာ အကြောင်း ပိုမိုလေ့လာပါ"</string> @@ -67,25 +67,25 @@ <string name="print_services_disabled_toast" msgid="9089060734685174685">"အချို့ပုံနှိပ်ဝန်ဆောင်မှုများကို ပိတ်ထားပါသည်"</string> <string name="print_searching_for_printers" msgid="6550424555079932867">"ပရင်တာများကို ရှာနေသည်"</string> <string name="print_no_print_services" msgid="8561247706423327966">"ပုံနှိပ်ထုတ်ယူရေး ဝန်ဆောင်မှုများ ဖွင့်မထားပါ"</string> - <string name="print_no_printers" msgid="4869403323900054866">"စာထုတ်စက် တစ်ခုမှ မတွေ့ရှိပါ"</string> + <string name="print_no_printers" msgid="4869403323900054866">"ပ တစ်ခုမှ မတွေ့ရှိပါ"</string> <string name="cannot_add_printer" msgid="7840348733668023106">"ပုံနှိပ်စက်များကို ထည့်၍မရပါ"</string> - <string name="select_to_add_printers" msgid="3800709038689830974">"ပုံနှိပ်စက်ထည့်ရန် ရွေးပါ"</string> + <string name="select_to_add_printers" msgid="3800709038689830974">"ပရင်တာထည့်ရန် ရွေးပါ"</string> <string name="enable_print_service" msgid="3482815747043533842">"ဖွင့်ရန် ရွေးပါ"</string> <string name="enabled_services_title" msgid="7036986099096582296">"ဖွင့်ထားသည့် ဝန်ဆောင်မှုများ"</string> <string name="recommended_services_title" msgid="3799434882937956924">"အကြံပြုထားသည့် ဝန်ဆောင်မှုများ"</string> <string name="disabled_services_title" msgid="7313253167968363211">"ပိတ်ထားသည့် ဝန်ဆောင်မှုများ"</string> <string name="all_services_title" msgid="5578662754874906455">"ဝန်ဆောင်မှုများ အားလုံး"</string> <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138"> - <item quantity="other">ပုံနှိပ်စက် <xliff:g id="COUNT_1">%1$s</xliff:g> ခုကို ရှာဖွေရန် စနစ်ထည့်သွင်းပါ</item> - <item quantity="one">ပုံနှိပ်စက် <xliff:g id="COUNT_0">%1$s</xliff:g> ခုကို ရှာဖွေရန် စနစ်ထည့်သွင်းပါ</item> + <item quantity="other">ပရင်တာ <xliff:g id="COUNT_1">%1$s</xliff:g> ခုကို ရှာဖွေရန် စနစ်ထည့်သွင်းပါ</item> + <item quantity="one">ပရင်တာ <xliff:g id="COUNT_0">%1$s</xliff:g> ခုကို ရှာဖွေရန် စနစ်ထည့်သွင်းပါ</item> </plurals> <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို စာထုတ်နေပါသည်"</string> <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို ပယ်ဖျက်နေပါသည်"</string> - <string name="failed_notification_title_template" msgid="2256217208186530973">"စာထုတ်စက်မှ အမှား <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <string name="blocked_notification_title_template" msgid="1175435827331588646">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ကိုစာထုတ်စက်ကငြင်းလိုက်သည်"</string> + <string name="failed_notification_title_template" msgid="2256217208186530973">"ပရင်တာမှ အမှား <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> + <string name="blocked_notification_title_template" msgid="1175435827331588646">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကိုပရင်တာက ငြင်းလိုက်သည်"</string> <string name="cancel" msgid="4373674107267141885">"မလုပ်တော့"</string> <string name="restart" msgid="2472034227037808749">"ပြန်စရန်"</string> - <string name="no_connection_to_printer" msgid="2159246915977282728">"စာထုတ်စက်နဲ့ ဆက်သွယ်ထားမှု မရှိပါ"</string> + <string name="no_connection_to_printer" msgid="2159246915977282728">"ပရင်တာနှင့် ဆက်သွယ်ထားမှု မရှိပါ"</string> <string name="reason_unknown" msgid="5507940196503246139">"မသိ"</string> <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ကိုသုံးမလား။"</string> <string name="print_service_security_warning_summary" msgid="1427434625361692006">"သင်၏ စာရွက်စာတမ်းများသည် ပရင်တာထံသို့ သွားစဉ် ဆာဗာ တစ်ခု သို့မဟုတ် ပိုများပြီး ဖြတ်ကျော်နိုင်ရသည်။"</string> @@ -105,7 +105,7 @@ <string name="print_write_error_message" msgid="5787642615179572543">"ဖိုင်သို့ မရေးနိုင်ခဲ့"</string> <string name="print_error_default_message" msgid="8602678405502922346">"လုပ်၍မရခဲ့ပါ။ ထပ်စမ်းကြည့်ပါ။"</string> <string name="print_error_retry" msgid="1426421728784259538">"ထပ်စမ်းကြည့်ရန်"</string> - <string name="print_error_printer_unavailable" msgid="8985614415253203381">"ဒီပရင်တာမှာ ယခုအချိန်မှာ မရနိုင်ပါ။"</string> + <string name="print_error_printer_unavailable" msgid="8985614415253203381">"ဤပရင်တာသည် ယခုအချိန်တွင် မရနိုင်ပါ။"</string> <string name="print_cannot_load_page" msgid="6179560924492912009">"အစမ်းကြည့်ခြင်းကို ပြသ၍မရပါ"</string> <string name="print_preparing_preview" msgid="3939930735671364712">"အစမ်းကြည့်ရန် ပြင်ဆင်နေ…"</string> </resources> diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java index f5641bd84619..83a838f54d28 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java @@ -26,6 +26,7 @@ import android.widget.Toolbar; import androidx.annotation.Nullable; import com.google.android.material.appbar.CollapsingToolbarLayout; +import com.google.android.material.resources.TextAppearanceConfig; /** * A base Activity that has a collapsing toolbar layout is used for the activities intending to @@ -39,7 +40,8 @@ public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + // Force loading font synchronously for collapsing toolbar layout + TextAppearanceConfig.setShouldLoadFontSynchronously(true); super.setContentView(R.layout.collapsing_toolbar_base_layout); mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar); diff --git a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml index 3f0a06c68689..50f69d1d692a 100644 --- a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml +++ b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml @@ -64,7 +64,9 @@ style="@style/TextAppearance.EntityHeaderSummary" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="2dp"/> + android:layout_marginTop="2dp" + android:singleLine="false" + android:textAlignment="center"/> <TextView android:id="@+id/entity_header_second_summary" diff --git a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java index 6560a181d352..ed447f873610 100644 --- a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java +++ b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java @@ -25,6 +25,7 @@ import android.view.animation.Interpolator; import androidx.core.os.BuildCompat; +import com.google.android.material.transition.platform.FadeThroughProvider; import com.google.android.material.transition.platform.MaterialSharedAxis; import com.google.android.material.transition.platform.SlideDistanceProvider; @@ -35,6 +36,7 @@ public class SettingsTransitionHelper { private static final String TAG = "SettingsTransitionHelper"; private static final long DURATION = 450L; + private static final float FADE_THROUGH_THRESHOLD = 0.22F; private static MaterialSharedAxis createSettingsSharedAxis(Context context, boolean forward) { final MaterialSharedAxis transition = new MaterialSharedAxis(MaterialSharedAxis.X, forward); @@ -48,12 +50,14 @@ public class SettingsTransitionHelper { forwardDistanceProvider.setSlideDistance(distance); transition.setDuration(DURATION); + final FadeThroughProvider fadeThroughProvider = + (FadeThroughProvider) transition.getSecondaryAnimatorProvider(); + fadeThroughProvider.setProgressThreshold(FADE_THROUGH_THRESHOLD); + final Interpolator interpolator = AnimationUtils.loadInterpolator(context, R.interpolator.fast_out_extra_slow_in); transition.setInterpolator(interpolator); - // TODO(b/177480673): Update fade through threshold once (cl/362065364) is released - return transition; } diff --git a/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml b/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml index 0287b1f064d0..4d6e1b7f0ac8 100644 --- a/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml +++ b/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml @@ -19,9 +19,10 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="?android:attr/listPreferredItemHeight" - android:paddingStart="20dp" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:paddingBottom="16dp" + android:paddingTop="8dp" android:background="?android:attr/selectableItemBackground" android:clipToPadding="false"> @@ -29,8 +30,6 @@ android:id="@android:id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingBottom="16dp" - android:paddingTop="16dp" android:clickable="false" android:longClickable="false" android:maxLines="10" diff --git a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml b/packages/SettingsLib/TopIntroPreference/res/values/styles.xml index e7eb9f495310..65869b5580b5 100644 --- a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml +++ b/packages/SettingsLib/TopIntroPreference/res/values/styles.xml @@ -17,7 +17,7 @@ <resources> <style name="TextAppearance.TopIntroText" parent="@*android:style/TextAppearance.DeviceDefault"> - <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> <item name="android:textSize">14sp</item> <item name="android:textColor">?android:attr/textColorSecondary</item> </style> diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index fbb84fdfcedc..ccbcb8920de3 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -256,4 +256,7 @@ <!-- Default for Settings.Secure.ACCESSIBILITY_BUTTON_MODE --> <integer name="def_accessibility_button_mode">1</integer> + <!-- Default for Settings.Secure.ONE_HANDED_MODE_ACTIVATED --> + <bool name="def_one_handed_mode_activated">false</bool> + </resources> diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 72fb23797f0d..1cfdff8e24ed 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -173,6 +173,7 @@ public class SecureSettings { Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY, + Settings.Secure.ONE_HANDED_MODE_ACTIVATED, Settings.Secure.ONE_HANDED_MODE_ENABLED, Settings.Secure.ONE_HANDED_MODE_TIMEOUT, Settings.Secure.TAPS_APP_TO_EXIT, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java index c0e4df54c560..8f7f1faa4d91 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java @@ -138,6 +138,7 @@ public class GlobalSettingsValidators { new InclusiveIntegerRangeValidator( /* first= */Global.ONE_HANDED_KEYGUARD_SIDE_LEFT, /* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT)); + VALIDATORS.put(Global.DISABLE_WINDOW_BLURS, BOOLEAN_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index 4872aa4820ff..36f5dba61355 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -262,6 +262,7 @@ public class SecureSettingsValidators { VALIDATORS.put( Secure.ACCESSIBILITY_BUTTON_TARGETS, ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR); + VALIDATORS.put(Secure.ONE_HANDED_MODE_ACTIVATED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.ONE_HANDED_MODE_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.ONE_HANDED_MODE_TIMEOUT, ANY_INTEGER_VALIDATOR); VALIDATORS.put(Secure.TAPS_APP_TO_EXIT, BOOLEAN_VALIDATOR); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 635434b5f7ba..2f54e2124247 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -553,6 +553,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, GlobalSettingsProto.Development.ENABLE_NON_RESIZABLE_MULTI_WINDOW); + dumpSetting(s, p, + Settings.Global.DISABLE_WINDOW_BLURS, + GlobalSettingsProto.Development.DISABLE_WINDOW_BLURS); p.end(developmentToken); final long deviceToken = p.start(GlobalSettingsProto.DEVICE); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 2e90d369a883..941f47f52551 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -3401,7 +3401,7 @@ public class SettingsProvider extends ContentProvider { } private final class UpgradeController { - private static final int SETTINGS_VERSION = 201; + private static final int SETTINGS_VERSION = 202; private final int mUserId; @@ -4959,6 +4959,22 @@ public class SettingsProvider extends ContentProvider { currentVersion = 201; } + if (currentVersion == 201) { + // Version 201: Set the default value for Secure Settings: + final SettingsState secureSettings = getSecureSettingsLocked(userId); + final Setting oneHandedModeActivated = secureSettings.getSettingLocked( + Secure.ONE_HANDED_MODE_ACTIVATED); + if (oneHandedModeActivated.isNull()) { + final boolean defOneHandedModeActivated = getContext().getResources() + .getBoolean(R.bool.def_one_handed_mode_activated); + secureSettings.insertSettingLocked( + Secure.ONE_HANDED_MODE_ACTIVATED, + defOneHandedModeActivated ? "1" : "0", null, true, + SettingsState.SYSTEM_PACKAGE_NAME); + } + currentVersion = 202; + } + // vXXX: Add new settings above this point. if (currentVersion != newVersion) { diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 150d10db2692..22e38f4008da 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -231,6 +231,7 @@ public class SettingsBackupTest { Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR, Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH, Settings.Global.DEVICE_DEMO_MODE, + Settings.Global.DISABLE_WINDOW_BLURS, Settings.Global.BATTERY_SAVER_CONSTANTS, Settings.Global.BATTERY_TIP_CONSTANTS, Settings.Global.DEFAULT_SM_DP_PLUS, diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index 947ae8af8f75..6d6bc07c01b5 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -191,23 +191,11 @@ class ActivityLaunchAnimator(context: Context) { fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {} /** - * The animation was cancelled remotely. Note that [onLaunchAnimationEnd] will still be - * called after this if the animation was already started, i.e. if [onLaunchAnimationStart] - * was called before the cancellation. + * The animation was cancelled. Note that [onLaunchAnimationEnd] will still be called after + * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called + * before the cancellation. */ fun onLaunchAnimationCancelled() {} - - /** - * The remote animation was not started within the expected time. It timed out and will - * never [start][onLaunchAnimationStart]. - */ - fun onLaunchAnimationTimedOut() {} - - /** - * The animation was aborted because the opening window was not found. It will never - * [start][onLaunchAnimationStart]. - */ - fun onLaunchAnimationAborted() {} } /** The state of an expandable view during an [ActivityLaunchAnimator] animation. */ @@ -332,7 +320,7 @@ class ActivityLaunchAnimator(context: Context) { if (window == null) { removeTimeout() invokeCallback(iCallback) - controller.onLaunchAnimationAborted() + controller.onLaunchAnimationCancelled() return } @@ -486,7 +474,7 @@ class ActivityLaunchAnimator(context: Context) { } timedOut = true - controller.onLaunchAnimationTimedOut() + controller.onLaunchAnimationCancelled() } override fun onAnimationCancelled() { diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java index 4142e517243f..b75252b46785 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java @@ -58,7 +58,6 @@ public interface FalsingManager { /** Returns true if the gesture should be rejected. */ boolean isFalseTouch(int interactionType); - /** * Does basic checking to see if gesture looks like a tap. * @@ -127,8 +126,19 @@ public interface FalsingManager { /** Removes a {@link FalsingBeliefListener}. */ void removeFalsingBeliefListener(FalsingBeliefListener listener); + /** Adds a {@link FalsingTapListener}. */ + void addTapListener(FalsingTapListener falsingTapListener); + + /** Removes a {@link FalsingTapListener}. */ + void removeTapListener(FalsingTapListener falsingTapListener); + /** Listener that is alerted when falsing belief level crosses a predfined threshold. */ interface FalsingBeliefListener { void onFalse(); } + + /** Listener that is alerted when a double tap is required to confirm a single tap. */ + interface FalsingTapListener { + void onDoubleTapRequired(); + } } 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 ca1320448726..2213d1c5c844 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 @@ -46,6 +46,15 @@ public abstract class QSTileView extends LinearLayout { * background circle/peripherals. To retrieve only the inner icon, use {@link #getIcon()}. */ public abstract View getIconWithBackground(); + + /** + * Returns the {@link View} containing the icon on the right + * + * @see com.android.systemui.qs.tileimpl.QSTileViewHorizontal#sideView + */ + public View getSecondaryIcon() { + return null; + } public abstract void init(QSTile tile); public abstract void onStateChanged(State state); @@ -54,4 +63,8 @@ public abstract class QSTileView extends LinearLayout { public View getLabelContainer() { return null; } + + public View getSecondaryLabel() { + return null; + } } diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml index c5ba3d2a36cf..7f645ba81664 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml @@ -20,12 +20,14 @@ <!-- This is a view that shows general status information in Keyguard. --> <com.android.keyguard.KeyguardStatusView xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/res-auto" + xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/keyguard_status_view" android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center_horizontal|top"> + systemui:layout_constraintStart_toStartOf="parent" + systemui:layout_constraintEnd_toEndOf="parent" + systemui:layout_constraintTop_toTopOf="parent" + android:layout_width="0dp" + android:layout_height="wrap_content"> <LinearLayout android:id="@+id/status_view_container" android:layout_width="match_parent" @@ -70,5 +72,11 @@ android:letterSpacing="0.05" android:ellipsize="marquee" android:singleLine="true" /> + <FrameLayout + android:id="@+id/status_view_media_container" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="@dimen/qs_media_padding" + /> </LinearLayout> </com.android.keyguard.KeyguardStatusView> diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml index 696f215c751e..33aa228bd2a9 100644 --- a/packages/SystemUI/res-keyguard/values-in/strings.xml +++ b/packages/SystemUI/res-keyguard/values-in/strings.xml @@ -100,7 +100,7 @@ <string name="kg_password_puk_failed" msgid="6778867411556937118">"Operasi PUK SIM gagal!"</string> <string name="kg_pin_accepted" msgid="1625501841604389716">"Kode Diterima!"</string> <string name="keyguard_carrier_default" msgid="6359808469637388586">"Tidak ada layanan."</string> - <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Beralih metode masukan"</string> + <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Beralih metode input"</string> <string name="airplane_mode" msgid="2528005343938497866">"Mode pesawat"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pola diperlukan setelah perangkat dimulai ulang"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN diperlukan setelah perangkat dimulai ulang"</string> diff --git a/packages/SystemUI/res-keyguard/values/integers.xml b/packages/SystemUI/res-keyguard/values/integers.xml index 6f14dc9ba2e1..c6e90c0fcdec 100644 --- a/packages/SystemUI/res-keyguard/values/integers.xml +++ b/packages/SystemUI/res-keyguard/values/integers.xml @@ -20,4 +20,11 @@ 0x50 = bottom, 0x01 = center_horizontal --> <integer name="keyguard_host_view_gravity">0x51</integer> + + <!-- Gravity for the keyguard when it is in one-handed mode. This is ignored unless + can_use_one_handed_bouncer is true, _and_ the one handed bouncer is enabled in the device + config (com.android.internal.R.bool.config_enableOneHandedKeyguard) + + 0x50 = bottom, 0x01 = center_horizontal --> + <integer name="keyguard_host_view_one_handed_gravity">0x51</integer> </resources> diff --git a/packages/SystemUI/res/color/qs_security_footer_background_stroke.xml b/packages/SystemUI/res/color/qs_security_footer_background_stroke.xml new file mode 100644 index 000000000000..aa4d4e8c079d --- /dev/null +++ b/packages/SystemUI/res/color/qs_security_footer_background_stroke.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral1_100" android:alpha="0.8" /> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_media_art_background.xml index 30d026ec2948..95a187094113 100644 --- a/packages/SystemUI/res/drawable/qs_background_primary.xml +++ b/packages/SystemUI/res/drawable/qs_media_art_background.xml @@ -12,11 +12,9 @@ ~ 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. + ~ limitations under the License --> -<inset xmlns:android="http://schemas.android.com/apk/res/android"> - <shape> - <solid android:color="?attr/underSurfaceColor"/> - <corners android:radius="@dimen/notification_corner_radius" /> - </shape> -</inset>
\ No newline at end of file +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners android:radius="@dimen/qs_media_album_radius"/> +</shape> diff --git a/packages/SystemUI/res/drawable/qs_media_button_background.xml b/packages/SystemUI/res/drawable/qs_media_button_background.xml new file mode 100644 index 000000000000..2241abf130e3 --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_media_button_background.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:shape="rectangle"> + <stroke + android:color="?androidprv:attr/colorAccentPrimaryVariant" + android:width="1dp"/> + <corners android:radius="24dp"/> + <padding + android:left="16dp" + android:right="16dp" + android:top="8dp" + android:bottom="8dp" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/disabled_udfps_view.xml b/packages/SystemUI/res/drawable/qs_media_icon_background.xml index 13d3065d0860..a3a29865c104 100644 --- a/packages/SystemUI/res/layout/disabled_udfps_view.xml +++ b/packages/SystemUI/res/drawable/qs_media_icon_background.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. @@ -12,11 +12,12 @@ ~ 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. + ~ limitations under the License --> -<com.android.keyguard.DisabledUdfpsView - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/disabled_udfps_view" - android:layout_width="wrap_content" - android:layout_height="wrap_content" -/> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <solid android:color="?android:attr/colorBackground" /> + <size + android:width="20dp" + android:height="20dp" /> +</shape> diff --git a/packages/SystemUI/res-keyguard/drawable/qs_media_seamless_background.xml b/packages/SystemUI/res/drawable/qs_media_seamless_background.xml index 8e3768697f6a..e71c3d380be3 100644 --- a/packages/SystemUI/res-keyguard/drawable/qs_media_seamless_background.xml +++ b/packages/SystemUI/res/drawable/qs_media_seamless_background.xml @@ -20,6 +20,11 @@ <shape android:shape="rectangle"> <solid android:color="@color/media_seamless_border" /> <corners android:radius="24dp"/> + <padding + android:left="8dp" + android:right="8dp" + android:top="4dp" + android:bottom="4dp" /> </shape> </item> </ripple>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/qs_security_footer_background.xml b/packages/SystemUI/res/drawable/qs_security_footer_background.xml new file mode 100644 index 000000000000..7d370e9f0547 --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_security_footer_background.xml @@ -0,0 +1,37 @@ +<?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. + --> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:insetTop="@dimen/qs_security_footer_background_inset" + android:insetBottom="@dimen/qs_security_footer_background_inset" + > + <ripple + android:color="?android:attr/colorControlHighlight"> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <solid android:color="@android:color/white"/> + <corners android:radius="@dimen/qs_security_footer_corner_radius"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <stroke android:width="1dp" + android:color="@color/qs_security_footer_background_stroke"/> + <corners android:radius="@dimen/qs_security_footer_corner_radius"/> + </shape> + </item> + </ripple> +</inset>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml index 214c44a41c5c..335e0a464665 100644 --- a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml +++ b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml @@ -26,21 +26,22 @@ <FrameLayout android:layout_width="@*android:dimen/conversation_content_start" - android:layout_height="25dp" + android:layout_height="@dimen/conversation_single_line_face_pile_size" + android:paddingHorizontal="16dp" > <ImageView android:id="@*android:id/conversation_icon" - android:layout_width="20dp" - android:layout_height="20dp" - android:layout_gravity="center" + android:layout_width="@dimen/conversation_single_line_avatar_size" + android:layout_height="@dimen/conversation_single_line_avatar_size" + android:layout_gravity="center_vertical|end" /> <ViewStub android:id="@*android:id/conversation_face_pile" android:layout="@*android:layout/conversation_face_pile_layout" - android:layout_width="25dp" - android:layout_height="25dp" - android:layout_gravity="center" + android:layout_width="@dimen/conversation_single_line_face_pile_size" + android:layout_height="@dimen/conversation_single_line_face_pile_size" + android:layout_gravity="center_vertical|end" /> </FrameLayout> diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml index 7e944162fd0d..9210d05bf72e 100644 --- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml +++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml @@ -18,6 +18,7 @@ <!-- Layout for media recommendations inside QSPanel carousel --> <com.android.systemui.util.animation.TransitionLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/media_recommendations" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -84,4 +85,90 @@ android:layout_width="@dimen/qs_aa_media_rec_icon_size" android:layout_height="@dimen/qs_aa_media_rec_icon_size" /> + <!-- Constraints are set here as they are the same regardless of host --> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/qs_media_padding" + android:layout_marginStart="@dimen/qs_media_padding" + android:layout_marginEnd="@dimen/qs_media_padding" + android:id="@+id/remove_text" + android:fontFamily="@*android:string/config_headlineFontFamily" + android:singleLine="true" + android:textColor="?android:attr/textColorPrimary" + android:text="@string/controls_media_close_session" + android:gravity="center_horizontal|top" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toTopOf="@id/settings"/> + + <FrameLayout + android:id="@+id/settings" + android:background="@drawable/qs_media_light_source" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/qs_media_padding" + android:paddingBottom="@dimen/qs_media_padding" + android:minWidth="48dp" + android:minHeight="48dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/remove_text"> + + <TextView + android:layout_gravity="bottom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/qs_media_button_background" + android:fontFamily="@*android:string/config_headlineFontFamilyMedium" + android:textColor="?android:attr/textColorPrimary" + android:text="@string/controls_media_settings_button" /> + </FrameLayout> + + <FrameLayout + android:id="@+id/cancel" + android:background="@drawable/qs_media_light_source" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:paddingBottom="@dimen/qs_media_padding" + android:minWidth="48dp" + android:minHeight="48dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@id/dismiss" > + + <TextView + android:layout_gravity="bottom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/qs_media_button_background" + android:fontFamily="@*android:string/config_headlineFontFamilyMedium" + android:textColor="?android:attr/textColorPrimary" + android:text="@string/cancel" /> + </FrameLayout> + + <FrameLayout + android:id="@+id/dismiss" + android:background="@drawable/qs_media_light_source" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/qs_media_padding" + android:paddingBottom="@dimen/qs_media_padding" + android:minWidth="48dp" + android:minHeight="48dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent"> + + <TextView + android:layout_gravity="bottom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/qs_media_button_background" + android:fontFamily="@*android:string/config_headlineFontFamilyMedium" + android:textColor="?android:attr/textColorPrimary" + android:text="@string/controls_media_dismiss_button" + /> + </FrameLayout> + </com.android.systemui.util.animation.TransitionLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml index a4cf5eddb30e..cdced5a1be71 100644 --- a/packages/SystemUI/res/layout/media_view.xml +++ b/packages/SystemUI/res/layout/media_view.xml @@ -18,6 +18,7 @@ <!-- Layout for media controls inside QSPanel carousel --> <com.android.systemui.util.animation.TransitionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:id="@+id/qs_media_controls" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -32,8 +33,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - app:layout_constraintGuide_percent="0.5" - /> + app:layout_constraintGuide_percent="0.6" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/center_horizontal_guideline" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.5" /> <!-- As per Material Design on Biderectionality, this is forced to LTR in code --> <FrameLayout @@ -50,7 +57,7 @@ android:fontFamily="@*android:string/config_bodyFontFamily" android:textColor="?android:attr/textColorPrimary" android:gravity="start" - android:textSize="14sp" /> + android:textSize="12sp" /> <TextView android:id="@+id/media_total_time" @@ -60,11 +67,11 @@ android:fontFamily="@*android:string/config_bodyFontFamily" android:textColor="?android:attr/textColorPrimary" android:gravity="end" - android:textSize="14sp" /> + android:textSize="12sp" /> </FrameLayout> <!-- Actions must be ordered left-to-right even in RTL layout. However, they appear in a chain - with the album art, and must as a group appear at the end of that chain. This is + with the artist name, and must as a group appear at the end of that chain. This is accomplished by having all actions appear in a LTR chain within the parent, and then biasing it to the right side, then this barrier is used to bound the text views. --> <androidx.constraintlayout.widget.Barrier @@ -72,10 +79,10 @@ android:layout_width="0dp" android:layout_height="0dp" android:orientation="vertical" - app:layout_constraintTop_toBottomOf="@id/header_artist" + app:layout_constraintTop_toBottomOf="@id/header_title" app:barrierDirection="start" app:constraint_referenced_ids="action0,action1,action2,action3,action4" - app:layout_constraintHorizontal_bias="0" /> + /> <ImageButton android:id="@+id/action0" @@ -92,8 +99,8 @@ <ImageButton android:id="@+id/action2" style="@style/MediaPlayer.Button" - android:layout_width="52dp" - android:layout_height="52dp" /> + android:layout_width="48dp" + android:layout_height="48dp" /> <ImageButton android:id="@+id/action3" @@ -112,23 +119,27 @@ android:id="@+id/album_art" android:layout_width="@dimen/qs_media_album_size" android:layout_height="@dimen/qs_media_album_size" - android:layout_gravity="center_vertical" /> + android:layout_gravity="center_vertical" + android:background="@drawable/qs_media_art_background" + android:backgroundTint="?androidprv:attr/colorAccentSecondary" + android:clipToOutline="true" /> <!-- Seamless Output Switcher --> <LinearLayout android:id="@+id/media_seamless" android:layout_width="0dp" - android:layout_height="wrap_content" + android:layout_height="48dp" android:orientation="horizontal" - android:gravity="center" + android:gravity="top|end" + android:paddingTop="@dimen/qs_media_padding" + android:paddingEnd="@dimen/qs_media_padding" android:background="@drawable/qs_media_light_source" android:forceHasOverlappingRendering="false"> <LinearLayout android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_height="@dimen/qs_seamless_height" android:background="@drawable/qs_media_seamless_background" android:orientation="horizontal" - android:padding="6dp" android:contentDescription="@string/quick_settings_media_device_label"> <ImageView android:id="@+id/media_seamless_image" @@ -138,25 +149,28 @@ android:tint="?android:attr/colorPrimary" android:src="@*android:drawable/ic_media_seamless" /> <TextView - android:visibility="gone" android:id="@+id/media_seamless_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:layout_marginStart="8dp" + android:layout_marginStart="4dp" android:fontFamily="@*android:string/config_headlineFontFamily" android:singleLine="true" android:text="@*android:string/ext_media_seamless_action" android:textColor="?android:attr/colorPrimary" android:textDirection="locale" - android:textSize="14sp" /> + android:textSize="12sp" /> </LinearLayout> </LinearLayout> <ImageView android:id="@+id/media_seamless_fallback" - android:layout_width="@dimen/qs_seamless_icon_size" - android:layout_height="@dimen/qs_seamless_icon_size" + android:layout_width="@dimen/qs_seamless_fallback_icon_size" + android:layout_height="@dimen/qs_seamless_fallback_icon_size" + android:layout_marginTop="@dimen/qs_media_padding" + android:layout_marginBottom="@dimen/qs_media_padding" + android:layout_marginStart="@dimen/qs_center_guideline_padding" + android:layout_marginEnd="@dimen/qs_seamless_fallback_margin" android:tint="?android:attr/textColorPrimary" android:src="@drawable/ic_cast_connected" android:forceHasOverlappingRendering="false" /> @@ -170,27 +184,18 @@ android:layout_height="wrap_content" android:clickable="true" android:maxHeight="@dimen/qs_media_enabled_seekbar_height" - android:paddingVertical="@dimen/qs_media_enabled_seekbar_vertical_padding" + android:paddingTop="@dimen/qs_media_enabled_seekbar_vertical_padding" + android:layout_marginTop="-22dp" + android:paddingBottom="0dp" android:thumbTint="?android:attr/textColorPrimary" android:progressTint="?android:attr/textColorPrimary" - android:progressBackgroundTint="?android:attr/colorBackground" + android:progressBackgroundTint="?android:attr/textColorTertiary" android:splitTrack="false" /> - <!-- App name --> - <TextView - android:id="@+id/app_name" - android:textColor="?android:attr/textColorPrimary" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:singleLine="true" - android:fontFamily="@*android:string/config_headlineFontFamily" - android:textDirection="locale" - android:textSize="14sp" /> - <!-- Song name --> <TextView android:id="@+id/header_title" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" android:fontFamily="@*android:string/config_headlineFontFamilyMedium" android:singleLine="true" @@ -200,7 +205,7 @@ <!-- Artist name --> <TextView android:id="@+id/header_artist" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" android:fontFamily="@*android:string/config_headlineFontFamily" android:singleLine="true" @@ -209,39 +214,28 @@ <com.android.internal.widget.CachingIconView android:id="@+id/icon" - android:tint="?android:attr/textColorPrimary" - android:layout_width="48dp" - android:layout_height="48dp" - android:layout_margin="6dp" /> - - <!-- Constraints are set here as they are the same regardless of host --> - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/qs_media_panel_outer_padding" - android:layout_marginStart="@dimen/qs_media_panel_outer_padding" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" - android:id="@+id/media_text" - android:fontFamily="@*android:string/config_headlineFontFamilyMedium" - android:textColor="?android:attr/textColorSecondary" - android:text="@string/controls_media_title" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintBottom_toTopOf="@id/remove_text" - app:layout_constraintVertical_chainStyle="spread_inside"/> + android:tint="?android:attr/colorAccent" + android:layout_width="@dimen/qs_media_icon_size" + android:layout_height="@dimen/qs_media_icon_size" + android:background="@drawable/qs_media_icon_background" + /> + <!-- Long press menu --> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="@dimen/qs_media_panel_outer_padding" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" + android:layout_marginTop="@dimen/qs_media_padding" + android:layout_marginStart="@dimen/qs_media_padding" + android:layout_marginEnd="@dimen/qs_media_padding" android:id="@+id/remove_text" android:fontFamily="@*android:string/config_headlineFontFamily" android:singleLine="true" android:textColor="?android:attr/textColorPrimary" android:text="@string/controls_media_close_session" - app:layout_constraintTop_toBottomOf="@id/media_text" + android:gravity="center_horizontal|top" + app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toTopOf="@id/settings"/> <FrameLayout @@ -249,8 +243,8 @@ android:background="@drawable/qs_media_light_source" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="@dimen/qs_media_panel_outer_padding" - android:paddingBottom="@dimen/qs_media_panel_outer_padding" + android:layout_marginStart="@dimen/qs_media_padding" + android:paddingBottom="@dimen/qs_media_padding" android:minWidth="48dp" android:minHeight="48dp" app:layout_constraintBottom_toBottomOf="parent" @@ -261,6 +255,7 @@ android:layout_gravity="bottom" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:background="@drawable/qs_media_button_background" android:fontFamily="@*android:string/config_headlineFontFamilyMedium" android:textColor="?android:attr/textColorPrimary" android:text="@string/controls_media_settings_button" /> @@ -271,17 +266,19 @@ android:background="@drawable/qs_media_light_source" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" - android:paddingBottom="@dimen/qs_media_panel_outer_padding" + android:layout_marginEnd="8dp" + android:paddingBottom="@dimen/qs_media_padding" android:minWidth="48dp" android:minHeight="48dp" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@id/dismiss" > + app:layout_constraintEnd_toStartOf="@id/dismiss" + app:layout_constraintTop_toBottomOf="@id/remove_text"> <TextView android:layout_gravity="bottom" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:background="@drawable/qs_media_button_background" android:fontFamily="@*android:string/config_headlineFontFamilyMedium" android:textColor="?android:attr/textColorPrimary" android:text="@string/cancel" /> @@ -292,17 +289,19 @@ android:background="@drawable/qs_media_light_source" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" - android:paddingBottom="@dimen/qs_media_panel_outer_padding" + android:layout_marginEnd="@dimen/qs_media_padding" + android:paddingBottom="@dimen/qs_media_padding" android:minWidth="48dp" android:minHeight="48dp" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent"> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/remove_text"> <TextView android:layout_gravity="bottom" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:background="@drawable/qs_media_button_background" android:fontFamily="@*android:string/config_headlineFontFamilyMedium" android:textColor="?android:attr/textColorPrimary" android:text="@string/controls_media_dismiss_button" diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml index 112509272e58..ea644cfca68a 100644 --- a/packages/SystemUI/res/layout/notification_conversation_info.xml +++ b/packages/SystemUI/res/layout/notification_conversation_info.xml @@ -24,7 +24,6 @@ android:clipChildren="true" android:clipToPadding="true" android:orientation="vertical" - android:background="?android:attr/colorBackground" android:paddingStart="12dp"> <!-- Package Info --> diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml index c3f11138129f..666ec2705e5d 100644 --- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml +++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml @@ -21,5 +21,6 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" - android:clipChildren="true" + android:clipChildren="false" + android:clipToPadding="false" android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom" /> diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml index 30e52e9a763c..7cf3d014aa8a 100644 --- a/packages/SystemUI/res/layout/qs_panel.xml +++ b/packages/SystemUI/res/layout/qs_panel.xml @@ -21,13 +21,6 @@ android:clipToPadding="false" android:clipChildren="false" > - <!-- Main QS background --> - <View - android:id="@+id/quick_settings_background" - android:layout_width="match_parent" - android:layout_height="0dp" - android:background="@drawable/qs_background_primary" /> - <com.android.systemui.qs.NonInterceptingScrollView android:id="@+id/expanded_qs_scroll_view" android:layout_width="match_parent" @@ -36,6 +29,8 @@ android:elevation="4dp" android:importantForAccessibility="no" android:scrollbars="none" + android:clipChildren="false" + android:clipToPadding="false" android:layout_weight="1"> <com.android.systemui.qs.QSPanel android:id="@+id/quick_settings_panel" @@ -43,7 +38,9 @@ android:layout_height="wrap_content" android:background="@android:color/transparent" android:focusable="true" - android:accessibilityTraversalBefore="@android:id/edit"> + android:accessibilityTraversalBefore="@android:id/edit" + android:clipToPadding="false" + android:clipChildren="false"> <include layout="@layout/qs_footer_impl" /> <include layout="@layout/qs_media_divider" android:id="@+id/divider"/> diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml index 1f90476bb347..d8bb7e607a5d 100644 --- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml +++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml @@ -44,14 +44,6 @@ android:layout_weight="1" /> - <!-- Will hold security footer in landscape with media --> - <FrameLayout - android:id="@+id/header_text_container" - android:layout_height="match_parent" - android:layout_width="wrap_content" - android:gravity="center" - /> - <include layout="@layout/qs_carrier_group" android:id="@+id/carrier_group" android:layout_width="wrap_content" diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_security_footer.xml index db712e4b9f7a..de65fa0511bb 100644 --- a/packages/SystemUI/res/layout/quick_settings_footer.xml +++ b/packages/SystemUI/res/layout/quick_settings_security_footer.xml @@ -14,38 +14,39 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.systemui.util.NeverExactlyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:minHeight="48dp" +<com.android.systemui.util.DualHeightHorizontalLinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="@dimen/qs_security_footer_height" android:clickable="true" - android:paddingBottom="@dimen/qs_tile_padding_top" - android:paddingTop="@dimen/qs_tile_padding_top" - android:paddingStart="@dimen/qs_footer_padding_start" - android:paddingEnd="@dimen/qs_footer_padding_end" + android:padding="@dimen/qs_footer_padding" android:gravity="center_vertical" android:layout_gravity="center_vertical|center_horizontal" - android:background="@android:color/transparent"> + android:layout_marginVertical="@dimen/qs_security_footer_vertical_margin" + android:background="@drawable/qs_security_footer_background" + systemui:singleLineHeight="@dimen/qs_security_footer_single_line_height" + systemui:textViewId="@id/footer_text" + > <ImageView android:id="@+id/primary_footer_icon" android:layout_width="@dimen/qs_footer_icon_size" android:layout_height="@dimen/qs_footer_icon_size" android:gravity="start" - android:layout_marginEnd="8dp" + android:layout_marginEnd="12dp" android:contentDescription="@null" - android:tint="?android:attr/textColorPrimary" /> + android:tint="?android:attr/textColorSecondary" /> - <com.android.systemui.util.AutoMarqueeTextView + <TextView android:id="@+id/footer_text" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:singleLine="true" - android:ellipsize="marquee" - android:marqueeRepeatLimit="marquee_forever" - android:textAppearance="@style/TextAppearance.QS.TileLabel" - android:textColor="?android:attr/textColorPrimary"/> + android:maxLines="@integer/qs_security_footer_maxLines" + android:ellipsize="end" + android:textAppearance="@style/TextAppearance.QS.SecurityFooter" + android:textColor="?android:attr/textColorSecondary"/> <ImageView android:id="@+id/footer_icon" @@ -53,7 +54,7 @@ android:layout_height="@dimen/qs_footer_icon_size" android:layout_marginStart="8dp" android:contentDescription="@null" - android:src="@drawable/ic_info_outline" - android:tint="?android:attr/textColorPrimary" /> + android:src="@*android:drawable/ic_chevron_end" + android:tint="?android:attr/textColorSecondary" /> -</com.android.systemui.util.NeverExactlyLinearLayout> +</com.android.systemui.util.DualHeightHorizontalLinearLayout> diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml index 22cf2cb8cc1a..d0e3d3cc3945 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml @@ -55,6 +55,16 @@ android:layout_gravity="center_vertical|center_horizontal" android:visibility="gone" /> + <!-- Will hold security footer in landscape with media --> + <FrameLayout + android:id="@+id/header_text_container" + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:gravity="center" + /> + <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 46a698a092e3..52995ea41b03 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -37,10 +37,6 @@ android:layout_height="match_parent" android:layout_width="match_parent" /> - <include - layout="@layout/keyguard_status_view" - android:visibility="gone" /> - <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer android:layout_width="match_parent" android:layout_height="match_parent" @@ -49,6 +45,10 @@ android:clipToPadding="false" android:clipChildren="false"> + <include + layout="@layout/keyguard_status_view" + android:visibility="gone"/> + <include layout="@layout/dock_info_overlay" /> <FrameLayout diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml index 50b2f209d871..e5e8fe6ed5dc 100644 --- a/packages/SystemUI/res/layout/udfps_view.xml +++ b/packages/SystemUI/res/layout/udfps_view.xml @@ -20,7 +20,8 @@ android:id="@+id/udfps_view" android:layout_width="match_parent" android:layout_height="match_parent" - systemui:sensorTouchAreaCoefficient="0.5"> + systemui:sensorTouchAreaCoefficient="0.5" + android:contentDescription="@string/accessibility_fingerprint_label"> <ViewStub android:id="@+id/animation_view" diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml index 5f50fd400e7f..46e7d71c4c36 100644 --- a/packages/SystemUI/res/values-land/dimens.xml +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -30,6 +30,12 @@ --> <dimen name="qs_customize_header_min_height">44dp</dimen> + <dimen name="qs_security_footer_single_line_height">@*android:dimen/quick_qs_offset_height</dimen> + <dimen name="qs_footer_padding">14dp</dimen> + <dimen name="qs_security_footer_vertical_margin">0dp</dimen> + <dimen name="qs_security_footer_background_inset">12dp</dimen> + <dimen name="qs_security_footer_corner_radius">28dp</dimen> + <dimen name="battery_detail_graph_space_top">9dp</dimen> <dimen name="battery_detail_graph_space_bottom">9dp</dimen> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index f489fe846ff3..eb724425b5d8 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -189,5 +189,11 @@ <attr name="borderThickness" format="dimension" /> <attr name="borderColor" format="color" /> </declare-styleable> + + <declare-styleable name="DualHeightHorizontalLinearLayout"> + <attr name="singleLineHeight" format="dimension" /> + <attr name="singleLineVerticalPadding" format="dimension" /> + <attr name="textViewId" format="reference" /> + </declare-styleable> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 5feb95783245..120b3f8afd5d 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -375,7 +375,7 @@ <bool name="config_showNotificationGear">true</bool> <!-- Whether or not a background should be drawn behind a notification. --> - <bool name="config_drawNotificationBackground">true</bool> + <bool name="config_drawNotificationBackground">false</bool> <!-- Whether or the notifications can be shown and dismissed with a drag. --> <bool name="config_enableNotificationShadeDrag">true</bool> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index fff4a1b74e56..b76a4cea1004 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -139,7 +139,7 @@ <dimen name="notification_min_height_before_s">106dp</dimen> <!-- Height of a large notification in the status bar --> - <dimen name="notification_max_height">294dp</dimen> + <dimen name="notification_max_height">358dp</dimen> <!-- Height of a heads up notification in the status bar for legacy custom views --> <dimen name="notification_max_heads_up_height_legacy">128dp</dimen> @@ -157,7 +157,7 @@ <dimen name="notification_max_heads_up_height_increased">188dp</dimen> <!-- Side padding on the lockscreen on the side of notifications --> - <dimen name="notification_side_paddings">4dp</dimen> + <dimen name="notification_side_paddings">16dp</dimen> <!-- padding between the heads up and the statusbar --> <dimen name="heads_up_status_bar_padding">8dp</dimen> @@ -179,10 +179,10 @@ <dimen name="notification_min_interaction_height">40dp</dimen> <!-- Radius for notifications corners without adjacent notifications --> - <dimen name="notification_corner_radius">8dp</dimen> + <dimen name="notification_corner_radius">28dp</dimen> <!-- Radius for notifications corners with adjacent notifications --> - <dimen name="notification_corner_radius_small">0dp</dimen> + <dimen name="notification_corner_radius_small">4dp</dimen> <!-- the padding of the shelf icon container --> <dimen name="shelf_icon_container_padding">13dp</dimen> @@ -605,13 +605,18 @@ <dimen name="qs_header_carrier_separator_width">6dp</dimen> <dimen name="qs_status_separator">32dp</dimen> <dimen name="qs_carrier_margin_width">4dp</dimen> - <dimen name="qs_footer_padding_start">16dp</dimen> - <dimen name="qs_footer_padding_end">16dp</dimen> - <dimen name="qs_footer_icon_size">16dp</dimen> + <dimen name="qs_footer_icon_size">20dp</dimen> <dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen> <dimen name="qs_header_top_padding">15dp</dimen> <dimen name="qs_header_bottom_padding">14dp</dimen> + <dimen name="qs_footer_padding">20dp</dimen> + <dimen name="qs_security_footer_height">88dp</dimen> + <dimen name="qs_security_footer_single_line_height">48dp</dimen> + <dimen name="qs_security_footer_vertical_margin">8dp</dimen> + <dimen name="qs_security_footer_background_inset">0dp</dimen> + <dimen name="qs_security_footer_corner_radius">28dp</dimen> + <dimen name="qs_notif_collapsed_space">64dp</dimen> <dimen name="qs_container_bottom_padding">24dp</dimen> @@ -662,7 +667,7 @@ <dimen name="z_distance_between_notifications">0.5dp</dimen> <!-- The height of the divider between the individual notifications. --> - <dimen name="notification_divider_height">1dp</dimen> + <dimen name="notification_divider_height">2dp</dimen> <!-- The corner radius of the shadow behind the notification. --> <dimen name="notification_shadow_radius">0dp</dimen> @@ -675,7 +680,7 @@ <dimen name="notification_children_container_divider_height">0.5dp</dimen> <!-- The horizontal margin of the content in the notification shade --> - <dimen name="notification_shade_content_margin_horizontal">4dp</dimen> + <dimen name="notification_shade_content_margin_horizontal">16dp</dimen> <!-- The top margin for the notification children container in its non-expanded form. --> <dimen name="notification_children_container_margin_top"> @@ -691,8 +696,11 @@ <!-- Size of the face pile shown on one-line (children of a group) conversation notifications --> <dimen name="conversation_single_line_face_pile_size">25dp</dimen> + <!-- Size of the avatars within a face pile shown on one-line (children of a group) conversation notifications --> + <dimen name="conversation_single_line_face_pile_avatar_size">17dp</dimen> + <!-- Size of an avatar shown on one-line (children of a group) conversation notifications --> - <dimen name="conversation_single_line_avatar_size">20dp</dimen> + <dimen name="conversation_single_line_avatar_size">24dp</dimen> <!-- Border width for avatars in the face pile shown on one-line (children of a group) conversation notifications --> <dimen name="conversation_single_line_face_pile_protection_width">1dp</dimen> @@ -1246,26 +1254,31 @@ <!-- Size of media cards in the QSPanel carousel --> <dimen name="qs_media_padding">16dp</dimen> - <dimen name="qs_media_panel_outer_padding">16dp</dimen> - <dimen name="qs_media_album_size">120dp</dimen> + <dimen name="qs_media_album_size_small">72dp</dimen> + <dimen name="qs_media_album_size">92dp</dimen> <dimen name="qs_media_album_radius">14dp</dimen> - <dimen name="qs_media_icon_size">16dp</dimen> + <dimen name="qs_media_album_device_padding">26dp</dimen> + <dimen name="qs_media_info_margin">12dp</dimen> + <dimen name="qs_media_info_spacing">4dp</dimen> + <dimen name="qs_media_icon_size">20dp</dimen> + <dimen name="qs_media_icon_offset">4dp</dimen> <dimen name="qs_center_guideline_padding">10dp</dimen> - <dimen name="qs_seamless_icon_size">@dimen/qs_media_icon_size</dimen> + <dimen name="qs_media_action_spacing">4dp</dimen> + <dimen name="qs_media_action_top">8dp</dimen> + <dimen name="qs_seamless_height">24dp</dimen> + <dimen name="qs_seamless_icon_size">16dp</dimen> <dimen name="qs_seamless_fallback_icon_size">@dimen/qs_seamless_icon_size</dimen> - <dimen name="qs_seamless_fallback_end_margin">16dp</dimen> - <dimen name="qqs_media_spacing">16dp</dimen> + <dimen name="qs_seamless_fallback_margin">20dp</dimen> <dimen name="qs_footer_horizontal_margin">22dp</dimen> <dimen name="qs_media_disabled_seekbar_height">1dp</dimen> - <dimen name="qs_media_enabled_seekbar_height">3dp</dimen> - <dimen name="qs_media_enabled_seekbar_vertical_padding">15dp</dimen> - <dimen name="qs_media_disabled_seekbar_vertical_padding">16dp</dimen> + <dimen name="qs_media_enabled_seekbar_height">2dp</dimen> + <dimen name="qs_media_enabled_seekbar_vertical_padding">35dp</dimen> + <dimen name="qs_media_disabled_seekbar_vertical_padding">36dp</dimen> <!-- Size of Smartspace media recommendations cards in the QSPanel carousel --> <dimen name="qs_aa_media_rec_album_size">80dp</dimen> <dimen name="qs_aa_media_rec_icon_size">20dp</dimen> - <!-- Window magnification --> <dimen name="magnification_border_drag_size">35dp</dimen> <dimen name="magnification_outer_border_margin">15dp</dimen> diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml index 5827f4e6ad3a..6104588690e3 100644 --- a/packages/SystemUI/res/values/flags.xml +++ b/packages/SystemUI/res/values/flags.xml @@ -20,9 +20,8 @@ <bool name="flag_notification_pipeline2">true</bool> <bool name="flag_notification_pipeline2_rendering">false</bool> - <bool name="flag_notif_updates">false</bool> + <bool name="flag_notif_updates">true</bool> - <bool name="flag_shade_is_opaque">false</bool> <bool name="flag_monet">false</bool> <!-- b/171917882 --> diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml index b50b5c14b1fa..116403c931b3 100644 --- a/packages/SystemUI/res/values/integers.xml +++ b/packages/SystemUI/res/values/integers.xml @@ -22,6 +22,8 @@ <integer name="qs_footer_actions_width">0</integer> <integer name="qs_footer_actions_weight">1</integer> + <integer name="qs_security_footer_maxLines">2</integer> + <integer name="magnification_default_scale">2</integer> <!-- The position of the volume dialog on the screen. diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index c117069f794b..bbb551996cd8 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -338,6 +338,8 @@ <string name="accessibility_voice_assist_button">Voice Assist</string> <!-- Content description of the unlock button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_unlock_button">Unlock</string> + <!-- Content description of the lock icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_lock_icon">Device locked</string> <!-- Content description hint of the unlock button when fingerprint is on (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_waiting_for_fingerprint">Waiting for fingerprint</string> <!-- Accessibility action of the unlock button when fingerpint is on (not shown on the screen). [CHAR LIMIT=NONE] --> @@ -2725,7 +2727,7 @@ <string name="accessibility_floating_button_action_move_bottom_right">Move bottom right</string> <!-- Action in accessibility menu to move the accessibility floating button to the edge and hide it to half. [CHAR LIMIT=30]--> <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half">Move to edge and hide</string> - <!-- Action in accessibility menu to move the accessibility floating button out the edge and show. [CHAR LIMIT=30]--> + <!-- Action in accessibility menu to move the accessibility floating button out the edge and show. [CHAR LIMIT=36]--> <string name="accessibility_floating_button_action_move_out_edge_and_show">Move out edge and show</string> <!-- Device Controls strings --> @@ -2824,10 +2826,10 @@ <!-- Title for media controls [CHAR_LIMIT=50] --> <string name="controls_media_title">Media</string> - <!-- Explanation for closing controls associated with a specific media session [CHAR_LIMIT=NONE] --> - <string name="controls_media_close_session">Hide the current session.</string> - <!-- Explanation that controls associated with a specific media session are active [CHAR_LIMIT=NONE] --> - <string name="controls_media_active_session">Current session cannot be hidden.</string> + <!-- Explanation for closing controls associated with a specific media session [CHAR_LIMIT=50] --> + <string name="controls_media_close_session">Hide this media session?</string> + <!-- Explanation that controls associated with a specific media session are active [CHAR_LIMIT=50] --> + <string name="controls_media_active_session">The current media session cannot be hidden.</string> <!-- Label for a button that will hide media controls [CHAR_LIMIT=30] --> <string name="controls_media_dismiss_button">Dismiss</string> <!-- Label for button to resume media playback [CHAR_LIMIT=NONE] --> @@ -2958,4 +2960,18 @@ <!-- Secondary label for alarm tile when there is no next alarm information [CHAR LIMIT=20] --> <string name="qs_alarm_tile_no_alarm">No alarm set</string> + + <!-- Accessibility label for fingerprint sensor [CHAR LIMIT=NONE] --> + <string name="accessibility_fingerprint_label">Fingerprint sensor</string> + <!-- Accessibility label for disabled udfps sensor [CHAR LIMIT=NONE] --> + <string name="accessibility_udfps_disabled_button">Fingerprint sensor disabled</string> + <!-- Accessibility action for tapping on an affordance that will bring up the user's + pin/pattern/password bouncer (ie: "Double tap to authenticate") [CHAR LIMIT=NONE] --> + <string name="accessibility_authenticate_hint">authenticate</string> + <!-- Accessibility action for tapping on an affordance on an unlocked lock screen (ie: "Double + tap to enter device") [CHAR LIMIT=NONE] --> + <string name="accessibility_enter_hint">enter device</string> + <!-- Message shown to suggest authentication using [CHAR LIMIT=60]--> + <string name="keyguard_try_fingerprint">Use fingerprint to open</string> + </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 5da75a1f2a70..2e45acc2cbfa 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -220,6 +220,11 @@ <item name="android:textSize">@dimen/celltile_rat_type_size</item> </style> + <style name="TextAppearance.QS.SecurityFooter"> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="android:textSize">@dimen/qs_tile_text_size</item> + </style> + <style name="TextAppearance.QS.Status" parent="TextAppearance.QS.TileLabel.Secondary"> <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> <item name="android:textColor">@color/dark_mode_qs_icon_color_single_tone</item> diff --git a/packages/SystemUI/res/xml/media_collapsed.xml b/packages/SystemUI/res/xml/media_collapsed.xml index f83e3a1d9b26..9bd462e66e3b 100644 --- a/packages/SystemUI/res/xml/media_collapsed.xml +++ b/packages/SystemUI/res/xml/media_collapsed.xml @@ -21,96 +21,82 @@ android:id="@+id/icon" android:layout_width="@dimen/qs_media_icon_size" android:layout_height="@dimen/qs_media_icon_size" - android:layout_marginStart="18dp" - android:layout_marginTop="@dimen/qs_media_panel_outer_padding" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintStart_toEndOf="@id/album_art" - /> - - <Constraint - android:id="@+id/app_name" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/qs_center_guideline_padding" - android:layout_marginStart="8dp" - app:layout_constraintTop_toTopOf="@id/icon" - app:layout_constraintBottom_toBottomOf="@id/icon" - app:layout_constraintStart_toEndOf="@id/icon" - app:layout_constraintEnd_toStartOf="@id/center_vertical_guideline" - app:layout_constrainedWidth="true" - app:layout_constraintHorizontal_bias="0" + android:translationY="@dimen/qs_media_icon_offset" + android:translationX="@dimen/qs_media_icon_offset" + app:layout_constraintEnd_toEndOf="@id/album_art" + app:layout_constraintBottom_toBottomOf="@id/album_art" /> <Constraint android:id="@+id/media_seamless" android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_height="48dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toEndOf="@id/center_vertical_guideline" + app:layout_constraintBottom_toTopOf="@id/center_horizontal_guideline" app:layout_constraintHorizontal_chainStyle="spread_inside" app:layout_constraintHorizontal_bias="1" app:layout_constrainedWidth="true" app:layout_constraintWidth_min="48dp" app:layout_constraintHeight_min="48dp" + android:paddingTop="@dimen/qs_media_padding" + android:paddingEnd="@dimen/qs_media_padding" android:layout_marginStart="@dimen/qs_center_guideline_padding" + android:layout_marginBottom="4dp" /> <Constraint android:id="@+id/media_seamless_fallback" android:layout_width="@dimen/qs_seamless_fallback_icon_size" android:layout_height="@dimen/qs_seamless_fallback_icon_size" - android:layout_marginEnd="@dimen/qs_seamless_fallback_end_margin" + android:layout_marginTop="@dimen/qs_media_padding" + android:layout_marginBottom="@dimen/qs_media_padding" android:layout_marginStart="@dimen/qs_center_guideline_padding" + android:layout_marginEnd="@dimen/qs_seamless_fallback_margin" android:alpha="0.5" android:visibility="gone" app:layout_constraintHorizontal_bias="1" - app:layout_constraintTop_toTopOf="@id/icon" - app:layout_constraintBottom_toBottomOf="@id/icon" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toTopOf="@id/center_horizontal_guideline" app:layout_constraintStart_toEndOf="@id/center_vertical_guideline" app:layout_constraintEnd_toEndOf="parent" /> <Constraint android:id="@+id/album_art" - android:layout_width="@dimen/qs_media_album_size" - android:layout_height="@dimen/qs_media_album_size" - android:layout_marginTop="@dimen/qs_media_panel_outer_padding" - android:layout_marginStart="@dimen/qs_media_panel_outer_padding" - android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" + android:layout_width="@dimen/qs_media_album_size_small" + android:layout_height="@dimen/qs_media_album_size_small" + android:layout_marginTop="@dimen/qs_media_padding" + android:layout_marginStart="@dimen/qs_media_padding" + android:layout_marginBottom="@dimen/qs_media_padding" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toStartOf="@id/media_action_barrier" - app:layout_constraintHorizontal_bias="0" /> <!-- Song name --> <Constraint android:id="@+id/header_title" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/qqs_media_spacing" - android:layout_marginStart="@dimen/qqs_media_spacing" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" + android:layout_marginStart="@dimen/qs_media_info_margin" + android:layout_marginEnd="@dimen/qs_center_guideline_padding" app:layout_constrainedWidth="true" - app:layout_constraintTop_toBottomOf="@id/icon" - app:layout_constraintBottom_toTopOf="@id/header_artist" + app:layout_constraintBottom_toTopOf="@id/center_horizontal_guideline" app:layout_constraintStart_toEndOf="@id/album_art" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintEnd_toStartOf="@id/center_vertical_guideline" app:layout_constraintHorizontal_bias="0"/> <!-- Artist name --> <Constraint android:id="@+id/header_artist" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="3dp" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" - android:layout_marginBottom="@dimen/qqs_media_spacing" app:layout_constrainedWidth="true" - app:layout_constraintTop_toBottomOf="@id/header_title" + android:layout_marginTop="@dimen/qs_media_info_spacing" + app:layout_constraintTop_toTopOf="@id/center_horizontal_guideline" app:layout_constraintStart_toStartOf="@id/header_title" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintEnd_toStartOf="@id/media_action_barrier" app:layout_constraintHorizontal_bias="0"/> <!-- Seek Bar --> @@ -130,9 +116,6 @@ android:alpha="0.0" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="35dp" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" - android:layout_marginStart="@dimen/qs_media_panel_outer_padding" app:layout_constraintTop_toBottomOf="@id/album_art" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -143,15 +126,16 @@ android:id="@+id/action0" android:layout_width="48dp" android:layout_height="48dp" - android:layout_marginStart="@dimen/qqs_media_spacing" - android:layout_marginEnd="4dp" - android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" + android:layout_marginStart="@dimen/qs_media_padding" + android:layout_marginEnd="@dimen/qs_media_action_spacing" + android:layout_marginTop="@dimen/qs_media_action_spacing" android:visibility="gone" app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintTop_toBottomOf="@id/header_artist" + app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@id/action1" - app:layout_constraintHorizontal_bias="0" + app:layout_constraintHorizontal_bias="1" > </Constraint> @@ -159,10 +143,10 @@ android:id="@+id/action1" android:layout_width="48dp" android:layout_height="48dp" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" - android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" - app:layout_constraintTop_toBottomOf="@id/header_artist" + android:layout_marginStart="@dimen/qs_media_action_spacing" + android:layout_marginEnd="@dimen/qs_media_action_spacing" + android:layout_marginTop="@dimen/qs_media_action_spacing" + app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@id/action0" app:layout_constraintRight_toLeftOf="@id/action2" @@ -173,10 +157,10 @@ android:id="@+id/action2" android:layout_width="48dp" android:layout_height="48dp" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" - android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" - app:layout_constraintTop_toBottomOf="@id/header_artist" + android:layout_marginStart="@dimen/qs_media_action_spacing" + android:layout_marginEnd="@dimen/qs_media_action_spacing" + android:layout_marginTop="@dimen/qs_media_action_spacing" + app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@id/action1" app:layout_constraintRight_toLeftOf="@id/action3" @@ -187,10 +171,10 @@ android:id="@+id/action3" android:layout_width="48dp" android:layout_height="48dp" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" - android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" - app:layout_constraintTop_toBottomOf="@id/header_artist" + android:layout_marginStart="@dimen/qs_media_action_spacing" + android:layout_marginEnd="@dimen/qs_media_action_spacing" + android:layout_marginTop="@dimen/qs_media_action_spacing" + app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@id/action2" app:layout_constraintRight_toLeftOf="@id/action4" @@ -201,12 +185,12 @@ android:id="@+id/action4" android:layout_width="48dp" android:layout_height="48dp" - android:layout_marginStart="4dp" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" + android:layout_marginStart="@dimen/qs_media_action_spacing" + android:layout_marginEnd="@dimen/qs_media_padding" android:visibility="gone" - android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" + android:layout_marginTop="@dimen/qs_media_action_spacing" app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintTop_toBottomOf="@id/header_artist" + app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@id/action3" app:layout_constraintRight_toRightOf="parent" diff --git a/packages/SystemUI/res/xml/media_expanded.xml b/packages/SystemUI/res/xml/media_expanded.xml index 7c6772059695..fd04fa0723aa 100644 --- a/packages/SystemUI/res/xml/media_expanded.xml +++ b/packages/SystemUI/res/xml/media_expanded.xml @@ -21,30 +21,16 @@ android:id="@+id/icon" android:layout_width="@dimen/qs_media_icon_size" android:layout_height="@dimen/qs_media_icon_size" - android:layout_marginStart="18dp" - android:layout_marginTop="@dimen/qs_media_panel_outer_padding" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintStart_toEndOf="@id/album_art" - /> - - <Constraint - android:id="@+id/app_name" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/qs_center_guideline_padding" - android:layout_marginStart="8dp" - app:layout_constraintTop_toTopOf="@id/icon" - app:layout_constraintBottom_toBottomOf="@id/icon" - app:layout_constraintStart_toEndOf="@id/icon" - app:layout_constraintEnd_toStartOf="@id/center_vertical_guideline" - app:layout_constrainedWidth="true" - app:layout_constraintHorizontal_bias="0" - /> + android:translationY="@dimen/qs_media_icon_offset" + android:translationX="@dimen/qs_media_icon_offset" + app:layout_constraintEnd_toEndOf="@id/album_art" + app:layout_constraintBottom_toBottomOf="@id/album_art" + /> <Constraint android:id="@+id/media_seamless" android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_height="48dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toEndOf="@id/center_vertical_guideline" @@ -53,20 +39,23 @@ app:layout_constrainedWidth="true" app:layout_constraintWidth_min="48dp" app:layout_constraintHeight_min="48dp" + android:paddingTop="@dimen/qs_media_padding" + android:paddingEnd="@dimen/qs_media_padding" android:layout_marginStart="@dimen/qs_center_guideline_padding" - /> + android:layout_marginBottom="4dp" /> <Constraint android:id="@+id/media_seamless_fallback" android:layout_width="@dimen/qs_seamless_fallback_icon_size" android:layout_height="@dimen/qs_seamless_fallback_icon_size" - android:layout_marginEnd="@dimen/qs_seamless_fallback_end_margin" + android:layout_marginTop="@dimen/qs_media_padding" + android:layout_marginBottom="16dp" android:layout_marginStart="@dimen/qs_center_guideline_padding" + android:layout_marginEnd="@dimen/qs_seamless_fallback_margin" android:alpha="0.5" android:visibility="gone" app:layout_constraintHorizontal_bias="1" - app:layout_constraintTop_toTopOf="@id/icon" - app:layout_constraintBottom_toBottomOf="@id/icon" + app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toEndOf="@id/center_vertical_guideline" app:layout_constraintEnd_toEndOf="parent" /> @@ -75,9 +64,9 @@ android:id="@+id/album_art" android:layout_width="@dimen/qs_media_album_size" android:layout_height="@dimen/qs_media_album_size" - android:layout_marginTop="@dimen/qs_media_panel_outer_padding" - android:layout_marginStart="@dimen/qs_media_panel_outer_padding" - android:layout_marginBottom="@dimen/qqs_media_spacing" + android:layout_marginTop="@dimen/qs_media_padding" + android:layout_marginStart="@dimen/qs_media_padding" + android:layout_marginBottom="0dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" /> @@ -87,11 +76,11 @@ android:id="@+id/header_title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/qqs_media_spacing" - android:layout_marginStart="@dimen/qqs_media_spacing" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" + android:layout_marginTop="26dp" + android:layout_marginStart="@dimen/qs_media_info_margin" + android:layout_marginEnd="@dimen/qs_media_padding" app:layout_constrainedWidth="true" - app:layout_constraintTop_toBottomOf="@+id/icon" + app:layout_constraintTop_toTopOf="@+id/album_art" app:layout_constraintStart_toEndOf="@id/album_art" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0"/> @@ -101,10 +90,10 @@ android:id="@+id/header_artist" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" - android:layout_marginBottom="@dimen/qqs_media_spacing" - android:layout_marginTop="3dp" + android:layout_marginEnd="@dimen/qs_media_padding" + android:layout_marginBottom="@dimen/qs_media_padding" app:layout_constrainedWidth="true" + android:layout_marginTop="@dimen/qs_media_info_spacing" app:layout_constraintTop_toBottomOf="@id/header_title" app:layout_constraintStart_toStartOf="@id/header_title" app:layout_constraintEnd_toEndOf="parent" @@ -115,7 +104,6 @@ android:id="@+id/media_progress_bar" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="35dp" app:layout_constraintTop_toBottomOf="@id/header_artist" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -125,10 +113,9 @@ android:id="@+id/notification_media_progress_time" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="70dp" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" - android:layout_marginStart="@dimen/qs_media_panel_outer_padding" - app:layout_constraintTop_toBottomOf="@id/header_artist" + android:layout_marginEnd="@dimen/qs_media_padding" + android:layout_marginStart="@dimen/qs_media_padding" + app:layout_constraintTop_toBottomOf="@id/media_progress_bar" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> @@ -137,9 +124,10 @@ android:id="@+id/action0" android:layout_width="48dp" android:layout_height="48dp" - android:layout_marginTop="5dp" - android:layout_marginStart="@dimen/qs_media_panel_outer_padding" - android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" + android:layout_marginTop="@dimen/qs_media_action_top" + android:layout_marginStart="@dimen/qs_media_padding" + android:layout_marginEnd="@dimen/qs_media_action_spacing" + android:layout_marginBottom="@dimen/qs_media_padding" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@id/action1" @@ -151,12 +139,12 @@ android:id="@+id/action1" android:layout_width="48dp" android:layout_height="48dp" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" - android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" + android:layout_marginTop="@dimen/qs_media_action_top" + android:layout_marginStart="@dimen/qs_media_action_spacing" + android:layout_marginEnd="@dimen/qs_media_action_spacing" + android:layout_marginBottom="@dimen/qs_media_padding" app:layout_constraintLeft_toRightOf="@id/action0" app:layout_constraintRight_toLeftOf="@id/action2" - app:layout_constraintTop_toTopOf="@id/action0" app:layout_constraintTop_toBottomOf="@id/media_progress_bar" app:layout_constraintBottom_toBottomOf="parent"> </Constraint> @@ -165,9 +153,10 @@ android:id="@+id/action2" android:layout_width="48dp" android:layout_height="48dp" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" - android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" + android:layout_marginTop="@dimen/qs_media_action_top" + android:layout_marginStart="@dimen/qs_media_action_spacing" + android:layout_marginEnd="@dimen/qs_media_action_spacing" + android:layout_marginBottom="@dimen/qs_media_padding" app:layout_constraintLeft_toRightOf="@id/action1" app:layout_constraintRight_toLeftOf="@id/action3" app:layout_constraintTop_toBottomOf="@id/media_progress_bar" @@ -178,9 +167,10 @@ android:id="@+id/action3" android:layout_width="48dp" android:layout_height="48dp" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" - android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" + android:layout_marginTop="@dimen/qs_media_action_top" + android:layout_marginStart="@dimen/qs_media_action_spacing" + android:layout_marginEnd="@dimen/qs_media_action_spacing" + android:layout_marginBottom="@dimen/qs_media_padding" app:layout_constraintLeft_toRightOf="@id/action2" app:layout_constraintRight_toLeftOf="@id/action4" app:layout_constraintTop_toBottomOf="@id/media_progress_bar" @@ -191,9 +181,10 @@ android:id="@+id/action4" android:layout_width="48dp" android:layout_height="48dp" - android:layout_marginStart="4dp" - android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" - android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" + android:layout_marginTop="@dimen/qs_media_action_top" + android:layout_marginStart="@dimen/qs_media_action_spacing" + android:layout_marginEnd="@dimen/qs_media_padding" + android:layout_marginBottom="@dimen/qs_media_padding" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintLeft_toRightOf="@id/action3" app:layout_constraintRight_toRightOf="parent" diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java index 351dfd5b10c4..5708855b0a4f 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java @@ -101,6 +101,9 @@ public class RemoteTransitionCompat implements Parcelable { public RemoteTransitionCompat(RecentsAnimationListener recents, RecentsAnimationControllerCompat controller) { mTransition = new IRemoteTransition.Stub() { + final RecentsControllerWrap mRecentsSession = new RecentsControllerWrap(); + IBinder mToken = null; + @Override public void startAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, @@ -110,6 +113,7 @@ public class RemoteTransitionCompat implements Parcelable { final RemoteAnimationTargetCompat[] wallpapers = RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */); // TODO(b/177438007): Move this set-up logic into launcher's animation impl. + mToken = transition; // This transition is for opening recents, so recents is on-top. We want to draw // the current going-away task on top of recents, though, so move it to front WindowContainerToken pausingTask = null; @@ -127,9 +131,8 @@ public class RemoteTransitionCompat implements Parcelable { t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1); } t.apply(); - final RecentsAnimationControllerCompat wrapControl = - new RecentsControllerWrap(controller, info, finishedCallback, pausingTask); - recents.onAnimationStart(wrapControl, apps, wallpapers, new Rect(0, 0, 0, 0), + mRecentsSession.setup(controller, info, finishedCallback, pausingTask); + recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0), new Rect()); } @@ -137,7 +140,13 @@ public class RemoteTransitionCompat implements Parcelable { public void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, IBinder mergeTarget, IRemoteTransitionFinishedCallback finishedCallback) { - // TODO: hook up merge to onTaskAppeared. Until then, just ignore incoming merges. + if (!mergeTarget.equals(mToken)) return; + if (!mRecentsSession.merge(info, t, recents)) return; + try { + finishedCallback.onTransitionFinished(null /* wct */); + } catch (RemoteException e) { + Log.e(TAG, "Error merging transition.", e); + } } }; } @@ -159,19 +168,57 @@ public class RemoteTransitionCompat implements Parcelable { */ @VisibleForTesting static class RecentsControllerWrap extends RecentsAnimationControllerCompat { - private final RecentsAnimationControllerCompat mWrapped; - private final IRemoteTransitionFinishedCallback mFinishCB; - private final WindowContainerToken mPausingTask; - private final TransitionInfo mInfo; + private RecentsAnimationControllerCompat mWrapped = null; + private IRemoteTransitionFinishedCallback mFinishCB = null; + private WindowContainerToken mPausingTask = null; + private TransitionInfo mInfo = null; + private SurfaceControl mOpeningLeash = null; - RecentsControllerWrap(RecentsAnimationControllerCompat wrapped, TransitionInfo info, + void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info, IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask) { + if (mInfo != null) { + throw new IllegalStateException("Trying to run a new recents animation while" + + " recents is already active."); + } mWrapped = wrapped; mInfo = info; mFinishCB = finishCB; mPausingTask = pausingTask; } + @SuppressLint("NewApi") + boolean merge(TransitionInfo info, SurfaceControl.Transaction t, + RecentsAnimationListener recents) { + TransitionInfo.Change openingTask = null; + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + final TransitionInfo.Change change = info.getChanges().get(i); + if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) { + if (change.getTaskInfo() != null) { + if (openingTask != null) { + Log.w(TAG, " Expecting to merge a task-open, but got >1 opening " + + "tasks"); + } + openingTask = change; + } + } + } + if (openingTask == null) return false; + mOpeningLeash = openingTask.getLeash(); + if (openingTask.getContainer().equals(mPausingTask)) { + // In this case, we are "returning" to the already running app, so just consume + // the merge and do nothing. + return true; + } + // We are receiving a new opening task, so convert to onTaskAppeared. + final int layer = mInfo.getChanges().size() * 3; + t.reparent(mOpeningLeash, mInfo.getRootLeash()); + t.setLayer(mOpeningLeash, layer); + t.hide(mOpeningLeash); + t.apply(); + recents.onTaskAppeared(new RemoteAnimationTargetCompat(openingTask, layer)); + return true; + } + @Override public ThumbnailData screenshotTask(int taskId) { return mWrapped != null ? mWrapped.screenshotTask(taskId) : null; } @@ -198,25 +245,42 @@ public class RemoteTransitionCompat implements Parcelable { @Override @SuppressLint("NewApi") public void finish(boolean toHome, boolean sendUserLeaveHint) { + if (mFinishCB == null) { + Log.e(TAG, "Duplicate call to finish", new RuntimeException()); + return; + } + if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint); try { - if (!toHome && mPausingTask != null) { + if (!toHome && mPausingTask != null && mOpeningLeash == null) { // The gesture went back to opening the app rather than continuing with // recents, so end the transition by moving the app back to the top. final WindowContainerTransaction wct = new WindowContainerTransaction(); wct.reorder(mPausingTask, true /* onTop */); mFinishCB.onTransitionFinished(wct); } else { + if (mOpeningLeash != null) { + // TODO: the launcher animation should handle this + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + t.show(mOpeningLeash); + t.setAlpha(mOpeningLeash, 1.f); + t.apply(); + } mFinishCB.onTransitionFinished(null /* wct */); } } catch (RemoteException e) { Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e); } - if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint); // Release surface references now. This is apparently to free GPU // memory while doing quick operations (eg. during CTS). for (int i = 0; i < mInfo.getChanges().size(); ++i) { mInfo.getChanges().get(i).getLeash().release(); } + // Reset all members. + mWrapped = null; + mFinishCB = null; + mPausingTask = null; + mInfo = null; + mOpeningLeash = null; } @Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) { diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java index 60b677a4e561..825e008263fa 100644 --- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java @@ -21,12 +21,14 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Color; +import android.hardware.biometrics.BiometricSourceType; import android.icu.text.NumberFormat; import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.util.ViewController; @@ -35,13 +37,15 @@ import java.util.Objects; import java.util.TimeZone; /** - * Controller for an AnimatableClockView. + * Controller for an AnimatableClockView. Instantiated by {@link KeyguardClockSwitchController}. */ public class AnimatableClockController extends ViewController<AnimatableClockView> { private static final int FORMAT_NUMBER = 1234567890; private final StatusBarStateController mStatusBarStateController; private final BroadcastDispatcher mBroadcastDispatcher; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final KeyguardBypassController mBypassController; private final int mDozingColor = Color.WHITE; private int mLockScreenColor; @@ -59,12 +63,16 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie AnimatableClockView view, StatusBarStateController statusBarStateController, BroadcastDispatcher broadcastDispatcher, - BatteryController batteryController) { + BatteryController batteryController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + KeyguardBypassController bypassController) { super(view); mStatusBarStateController = statusBarStateController; mIsDozing = mStatusBarStateController.isDozing(); mDozeAmount = mStatusBarStateController.getDozeAmount(); mBroadcastDispatcher = broadcastDispatcher; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mBypassController = bypassController; mBurmeseNumerals = mBurmeseNf.format(FORMAT_NUMBER); mBurmeseLineSpacing = getContext().getResources().getFloat( @@ -98,14 +106,29 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie mStatusBarStateController.addCallback(mStatusBarStateListener); mIsDozing = mStatusBarStateController.isDozing(); mDozeAmount = mStatusBarStateController.getDozeAmount(); + mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); + refreshTime(); initColors(); } + private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback = + new KeyguardUpdateMonitorCallback() { + @Override + public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType, + boolean isStrongBiometric) { + if (biometricSourceType == BiometricSourceType.FACE + && mBypassController.canBypass()) { + mView.animateDisappear(); + } + } + }; + @Override protected void onViewDetached() { mBroadcastDispatcher.unregisterReceiver(mLocaleBroadcastReceiver); mStatusBarStateController.removeCallback(mStatusBarStateListener); + mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback); } /** diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java index 0d6f64f004f9..dc14f826bf7d 100644 --- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java +++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java @@ -27,6 +27,7 @@ import android.util.AttributeSet; import android.widget.TextView; import com.android.systemui.R; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import java.util.Calendar; import java.util.TimeZone; @@ -155,6 +156,21 @@ public class AnimatableClockView extends TextView { mLockScreenColor = lockScreenColor; } + void animateDisappear() { + if (mTextAnimator == null) { + return; + } + + setTextStyle( + 0 /* weight */, + -1 /* text size, no update */, + null /* color, no update */, + true /* animate */, + KeyguardBypassController.BYPASS_FADE_DURATION /* duration */, + 0 /* delay */, + null /* onAnimationEnd */); + } + void animateCharge(boolean isDozing) { if (mTextAnimator == null || mTextAnimator.isRunning()) { // Skip charge animation if dozing animation is already playing. diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index 5559a1818b4b..e92cae4506fc 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -24,8 +24,16 @@ import android.app.WallpaperManager; import android.app.smartspace.SmartspaceConfig; import android.app.smartspace.SmartspaceManager; import android.app.smartspace.SmartspaceSession; +import android.app.smartspace.SmartspaceTarget; +import android.content.Context; import android.content.Intent; +import android.content.pm.UserInfo; import android.content.res.Resources; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; import android.text.TextUtils; import android.text.format.DateFormat; import android.view.View; @@ -47,15 +55,18 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin.IntentStarter; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.stack.AnimationProperties; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.NotificationIconContainer; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.ViewController; +import com.android.systemui.util.settings.SecureSettings; import java.util.Locale; import java.util.TimeZone; @@ -90,10 +101,19 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS private SmartspaceSession mSmartspaceSession; private SmartspaceSession.OnTargetsAvailableListener mSmartspaceCallback; - private int mWallpaperTextColor; private ConfigurationController mConfigurationController; private ActivityStarter mActivityStarter; private FalsingManager mFalsingManager; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final KeyguardBypassController mBypassController; + private Handler mHandler; + private UserTracker mUserTracker; + private SecureSettings mSecureSettings; + private ContentObserver mSettingsObserver; + private boolean mShowSensitiveContentForCurrentUser; + private boolean mShowSensitiveContentForManagedUser; + private UserHandle mManagedUserHandle; + private UserTracker.Callback mUserTrackerCallback; /** * Listener for changes to the color palette. @@ -147,7 +167,12 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS ConfigurationController configurationController, SystemUIFactory systemUIFactory, ActivityStarter activityStarter, - FalsingManager falsingManager) { + FalsingManager falsingManager, + KeyguardUpdateMonitor keyguardUpdateMonitor, + KeyguardBypassController bypassController, + @Main Handler handler, + UserTracker userTracker, + SecureSettings secureSettings) { super(keyguardClockSwitch); mStatusBarStateController = statusBarStateController; mColorExtractor = colorExtractor; @@ -162,6 +187,11 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS mSystemUIFactory = systemUIFactory; mActivityStarter = activityStarter; mFalsingManager = falsingManager; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mBypassController = bypassController; + mHandler = handler; + mUserTracker = userTracker; + mSecureSettings = secureSettings; } /** @@ -185,19 +215,23 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large); mClockViewController = - new AnimatableClockController( - mView.findViewById(R.id.animatable_clock_view), - mStatusBarStateController, - mBroadcastDispatcher, - mBatteryController); + new AnimatableClockController( + mView.findViewById(R.id.animatable_clock_view), + mStatusBarStateController, + mBroadcastDispatcher, + mBatteryController, + mKeyguardUpdateMonitor, + mBypassController); mClockViewController.init(); mLargeClockViewController = - new AnimatableClockController( - mView.findViewById(R.id.animatable_clock_view_large), - mStatusBarStateController, - mBroadcastDispatcher, - mBatteryController); + new AnimatableClockController( + mView.findViewById(R.id.animatable_clock_view_large), + mStatusBarStateController, + mBroadcastDispatcher, + mBatteryController, + mKeyguardUpdateMonitor, + mBypassController); mLargeClockViewController.init(); mStatusBarStateController.addCallback(mStatusBarStateListener); @@ -248,15 +282,74 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS mSmartspaceSession = getContext().getSystemService(SmartspaceManager.class) .createSmartspaceSession( new SmartspaceConfig.Builder(getContext(), "lockscreen").build()); - mSmartspaceCallback = targets -> smartspaceDataPlugin.onTargetsAvailable(targets); + mSmartspaceCallback = targets -> { + targets.removeIf(this::filterSmartspaceTarget); + smartspaceDataPlugin.onTargetsAvailable(targets); + }; mSmartspaceSession.addOnTargetsAvailableListener(mUiExecutor, mSmartspaceCallback); - mSmartspaceSession.requestSmartspaceUpdate(); + mSettingsObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange, Uri uri) { + reloadSmartspace(); + } + }; + + mUserTrackerCallback = new UserTracker.Callback() { + public void onUserChanged(int newUser, Context userContext) { + reloadSmartspace(); + } + }; + mUserTracker.addCallback(mUserTrackerCallback, mUiExecutor); + + getContext().getContentResolver().registerContentObserver( + Settings.Secure.getUriFor( + Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS), + true, mSettingsObserver, UserHandle.USER_ALL); + reloadSmartspace(); } float dozeAmount = mStatusBarStateController.getDozeAmount(); mStatusBarStateListener.onDozeAmountChanged(dozeAmount, dozeAmount); } + @VisibleForTesting + boolean filterSmartspaceTarget(SmartspaceTarget t) { + if (!t.isSensitive()) return false; + + if (t.getUserHandle().equals(mUserTracker.getUserHandle())) { + return !mShowSensitiveContentForCurrentUser; + } + if (t.getUserHandle().equals(mManagedUserHandle)) { + return !mShowSensitiveContentForManagedUser; + } + + return false; + } + + private void reloadSmartspace() { + mManagedUserHandle = getWorkProfileUser(); + final String setting = Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS; + + mShowSensitiveContentForCurrentUser = + mSecureSettings.getIntForUser(setting, 0, mUserTracker.getUserId()) == 1; + if (mManagedUserHandle != null) { + int id = mManagedUserHandle.getIdentifier(); + mShowSensitiveContentForManagedUser = + mSecureSettings.getIntForUser(setting, 0, id) == 1; + } + + mSmartspaceSession.requestSmartspaceUpdate(); + } + + private UserHandle getWorkProfileUser() { + for (UserInfo userInfo : mUserTracker.getUserProfiles()) { + if (userInfo.isManagedProfile()) { + return userInfo.getUserHandle(); + } + } + return null; + } + private void updateWallpaperColor() { if (mSmartspaceView != null) { int color = Utils.getColorAttrDefaultColor(getContext(), R.attr.wallpaperTextColor); @@ -279,6 +372,14 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS } mStatusBarStateController.removeCallback(mStatusBarStateListener); mConfigurationController.removeCallback(mConfigurationListener); + + if (mSettingsObserver != null) { + getContext().getContentResolver().unregisterContentObserver(mSettingsObserver); + } + + if (mUserTrackerCallback != null) { + mUserTracker.removeCallback(mUserTrackerCallback); + } } /** @@ -427,4 +528,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS ConfigurationController.ConfigurationListener getConfigurationListener() { return mConfigurationListener; } + + @VisibleForTesting + ContentObserver getSettingsObserver() { + return mSettingsObserver; + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java index 31f1332b265c..d06c8bc6bffe 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java @@ -475,7 +475,18 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView> * configuration. */ public void updateResources() { - int gravity = mView.getResources().getInteger(R.integer.keyguard_host_view_gravity); + int gravity; + + Resources resources = mView.getResources(); + + if (resources.getBoolean(R.bool.can_use_one_handed_bouncer) + && resources.getBoolean( + com.android.internal.R.bool.config_enableOneHandedKeyguard)) { + gravity = resources.getInteger( + R.integer.keyguard_host_view_one_handed_gravity); + } else { + gravity = resources.getInteger(R.integer.keyguard_host_view_gravity); + } // Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout. // We're just changing the gravity here though (which can't be applied to RelativeLayout), diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index 9df7734a385f..3ab2cca09a29 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -35,6 +35,7 @@ import androidx.core.graphics.ColorUtils; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.R; +import com.android.systemui.statusbar.CrossFadeHelper; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -44,6 +45,7 @@ import java.io.PrintWriter; * - keyguard clock * - logout button (on certain managed devices) * - owner information (if set) + * - media player (split shade mode only) */ public class KeyguardStatusView extends GridLayout { private static final boolean DEBUG = KeyguardConstants.DEBUG; @@ -60,6 +62,7 @@ public class KeyguardStatusView extends GridLayout { private KeyguardSliceView mKeyguardSlice; private Runnable mPendingMarqueeStart; private Handler mHandler; + private View mMediaHostContainer; private float mDarkAmount = 0; private int mTextColor; @@ -148,6 +151,8 @@ public class KeyguardStatusView extends GridLayout { mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged); onSliceContentChanged(); + mMediaHostContainer = findViewById(R.id.status_view_media_container); + updateOwnerInfo(); updateDark(); } @@ -223,6 +228,9 @@ public class KeyguardStatusView extends GridLayout { } mDarkAmount = darkAmount; mClockView.setDarkAmount(darkAmount); + if (mMediaHostContainer.getVisibility() != View.GONE) { + CrossFadeHelper.fadeOut(mMediaHostContainer, darkAmount); + } updateDark(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java index 015c4e44185b..ecc8c0074e18 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java @@ -146,6 +146,13 @@ public interface KeyguardViewController { void startPreHideAnimation(Runnable finishRunnable); /** + * Blocks the current touch gesture from affecting the expansion amount of the notification + * panel. This is used after a completed unlock gesture to ignore further dragging before an + * ACTION_UP. + */ + void blockPanelExpansionFromCurrentTouch(); + + /** * @return the ViewRootImpl of the View where the Keyguard is mounted. */ ViewRootImpl getViewRootImpl(); diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 66ea2ad001fd..b5f2ab213559 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -29,9 +29,12 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.util.Log; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityNodeInfo; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import com.android.settingslib.Utils; import com.android.systemui.Dumpable; @@ -63,6 +66,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @NonNull private final KeyguardStateController mKeyguardStateController; @NonNull private final FalsingManager mFalsingManager; @NonNull private final AuthController mAuthController; + @NonNull private final AccessibilityManager mAccessibilityManager; private boolean mHasUdfpsOrFaceAuthFeatures; private boolean mUdfpsEnrolled; @@ -79,6 +83,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme private boolean mQsExpanded; private int mStatusBarState; private boolean mIsKeyguardShowing; + private boolean mUserUnlockedWithBiometric; private boolean mShowButton; private boolean mShowUnlockIcon; @@ -93,19 +98,17 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @NonNull KeyguardStateController keyguardStateController, @NonNull FalsingManager falsingManager, @NonNull AuthController authController, - @NonNull DumpManager dumpManager + @NonNull DumpManager dumpManager, + @NonNull AccessibilityManager accessibilityManager ) { super(view); - if (mView != null) { - mView.setOnClickListener(v -> onAffordanceClick()); - mView.setOnLongClickListener(v -> onAffordanceClick()); - } mStatusBarStateController = statusBarStateController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mAuthController = authController; mKeyguardViewController = keyguardViewController; mKeyguardStateController = keyguardStateController; mFalsingManager = falsingManager; + mAccessibilityManager = accessibilityManager; final Context context = view.getContext(); mButton = context.getResources().getDrawable( @@ -122,6 +125,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme } @Override + protected void onInit() { + mView.setAccessibilityDelegate(mAccessibilityDelegate); + } + + @Override protected void onViewAttached() { // we check this here instead of onInit since the FingeprintManager + FaceManager may not // have started up yet onInit @@ -148,7 +156,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mView.setLocation(new PointF(props[0], props[1]), props[2]); } - mIsKeyguardShowing = mKeyguardViewController.isShowing(); + updateKeyguardShowing(); + mUserUnlockedWithBiometric = false; mIsBouncerShowing = mKeyguardViewController.isBouncerShowing(); mIsDozing = mStatusBarStateController.isDozing(); mRunningFPS = mKeyguardUpdateMonitor.isFingerprintDetectionRunning(); @@ -163,6 +172,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); mStatusBarStateController.addCallback(mStatusBarStateListener); mKeyguardStateController.addCallback(mKeyguardStateCallback); + mAccessibilityManager.addTouchExplorationStateChangeListener( + mTouchExplorationStateChangeListener); updateVisibility(); } @@ -172,6 +183,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback); mStatusBarStateController.removeCallback(mStatusBarStateListener); mKeyguardStateController.removeCallback(mKeyguardStateCallback); + mAccessibilityManager.removeTouchExplorationStateChangeListener( + mTouchExplorationStateChangeListener); } public float getTop() { @@ -205,25 +218,62 @@ public class LockIconViewController extends ViewController<LockIconView> impleme } // these three states are mutually exclusive: - mShowButton = mUdfpsEnrolled && !mCanDismissLockScreen && !mRunningFPS && isLockScreen(); + mShowButton = mUdfpsEnrolled && !mCanDismissLockScreen && !mRunningFPS + && !mUserUnlockedWithBiometric && isLockScreen(); mShowUnlockIcon = mFaceAuthEnrolled & mCanDismissLockScreen && isLockScreen(); mShowLockIcon = !mUdfpsEnrolled && !mCanDismissLockScreen && isLockScreen() && mFaceAuthEnrolled; + updateClickListener(); if (mShowButton) { mView.setImageDrawable(mButton); mView.setVisibility(View.VISIBLE); + mView.setContentDescription(getResources().getString( + R.string.accessibility_udfps_disabled_button)); } else if (mShowUnlockIcon) { mView.setImageDrawable(mUnlockIcon); mView.setVisibility(View.VISIBLE); + mView.setContentDescription(getResources().getString( + R.string.accessibility_unlock_button)); } else if (mShowLockIcon) { mView.setImageDrawable(mLockIcon); mView.setVisibility(View.VISIBLE); + mView.setContentDescription(getResources().getString( + R.string.accessibility_lock_icon)); } else { mView.setVisibility(View.INVISIBLE); + mView.setContentDescription(null); } } + private final View.AccessibilityDelegate mAccessibilityDelegate = + new View.AccessibilityDelegate() { + private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityAuthenticateHint = + new AccessibilityNodeInfo.AccessibilityAction( + AccessibilityNodeInfoCompat.ACTION_CLICK, + getResources().getString(R.string.accessibility_authenticate_hint)); + private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityEnterHint = + new AccessibilityNodeInfo.AccessibilityAction( + AccessibilityNodeInfoCompat.ACTION_CLICK, + getResources().getString(R.string.accessibility_enter_hint)); + public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(v, info); + removeAllActions(info); + if (mShowButton || mShowLockIcon) { + info.addAction(mAccessibilityAuthenticateHint); + } else if (mShowUnlockIcon) { + info.addAction(mAccessibilityEnterHint); + } + } + + private void removeAllActions(AccessibilityNodeInfo info) { + info.removeAction(mAccessibilityAuthenticateHint); + info.removeAction(mAccessibilityEnterHint); + info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK); + mView.setLongClickable(false); + } + }; + private boolean isLockScreen() { return !mIsDozing && !mIsBouncerShowing @@ -231,6 +281,22 @@ public class LockIconViewController extends ViewController<LockIconView> impleme && mStatusBarState == StatusBarState.KEYGUARD; } + private void updateClickListener() { + if (mView != null) { + mView.setOnClickListener(v -> onAffordanceClick()); + if (mAccessibilityManager.isTouchExplorationEnabled()) { + mView.setOnLongClickListener(null); + } else { + mView.setOnLongClickListener(v -> onAffordanceClick()); + } + } + } + + private void updateKeyguardShowing() { + mIsKeyguardShowing = mKeyguardStateController.isShowing() + && !mKeyguardStateController.isKeyguardGoingAway(); + } + @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { pw.println(" mShowBouncerButton: " + mShowButton); @@ -242,6 +308,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme pw.println(" mIsKeyguardShowing: " + mIsKeyguardShowing); pw.println(" mIsDozing: " + mIsDozing); pw.println(" mIsBouncerShowing: " + mIsBouncerShowing); + pw.println(" mUserUnlockedWithBiometric: " + mUserUnlockedWithBiometric); pw.println(" mRunningFPS: " + mRunningFPS); pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen); pw.println(" mStatusBarState: " + StatusBarState.toShortString(mStatusBarState)); @@ -268,18 +335,20 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @Override public void onKeyguardBouncerChanged(boolean bouncer) { mIsBouncerShowing = bouncer; - mIsKeyguardShowing = mKeyguardStateController.isShowing(); updateVisibility(); } @Override public void onBiometricRunningStateChanged(boolean running, BiometricSourceType biometricSourceType) { + mUserUnlockedWithBiometric = + mKeyguardUpdateMonitor.getUserUnlockedWithBiometric( + KeyguardUpdateMonitor.getCurrentUser()); + if (biometricSourceType == FINGERPRINT) { mRunningFPS = running; + updateVisibility(); } - - updateVisibility(); } }; @@ -288,14 +357,25 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @Override public void onUnlockedChanged() { mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen(); + updateKeyguardShowing(); updateVisibility(); } + @Override public void onKeyguardShowingChanged() { - mIsKeyguardShowing = mKeyguardStateController.isShowing(); + updateKeyguardShowing(); mUdfpsEnrolled = mKeyguardUpdateMonitor.isUdfpsEnrolled(); mFaceAuthEnrolled = mKeyguardUpdateMonitor.isFaceEnrolled(); updateVisibility(); } + + @Override + public void onKeyguardFadingAwayChanged() { + updateKeyguardShowing(); + updateVisibility(); + } }; + + private final AccessibilityManager.TouchExplorationStateChangeListener + mTouchExplorationStateChangeListener = enabled -> updateClickListener(); } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index cbfdce5d0c69..351ae8298ff4 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -54,6 +54,7 @@ import com.android.systemui.model.SysUiState; import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.navigationbar.NavigationBarOverlayController; import com.android.systemui.navigationbar.NavigationModeController; +import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.PluginDependencyProvider; @@ -356,6 +357,7 @@ public class Dependency { @Inject Lazy<TelephonyListenerManager> mTelephonyListenerManager; @Inject Lazy<SystemStatusAnimationScheduler> mSystemStatusAnimationSchedulerLazy; @Inject Lazy<PrivacyDotViewController> mPrivacyDotViewControllerLazy; + @Inject Lazy<EdgeBackGestureHandler> mEdgeBackGestureHandler; @Inject public Dependency() { @@ -568,6 +570,7 @@ public class Dependency { mProviders.put(SystemStatusAnimationScheduler.class, mSystemStatusAnimationSchedulerLazy::get); mProviders.put(PrivacyDotViewController.class, mPrivacyDotViewControllerLazy::get); + mProviders.put(EdgeBackGestureHandler.class, mEdgeBackGestureHandler::get); Dependency.setInstance(this); } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java index d89dff5027a7..5502a20ce398 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java @@ -371,6 +371,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout mAdapter.notifyDataSetChanged(); updateRadiusWith(mSizeType, mRadiusType, mTargets.size()); + updateScrollModeWith(hasExceededMaxLayoutHeight()); setSystemGestureExclusion(); fadeOut(); @@ -614,6 +615,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout updateColor(); updateStrokeWith(newConfig.uiMode, mAlignment); updateLocationWith(mAlignment, mPercentageY); + updateScrollModeWith(hasExceededMaxLayoutHeight()); } @VisibleForTesting @@ -679,6 +681,12 @@ public class AccessibilityFloatingMenuView extends FrameLayout mListView.setLayoutParams(layoutParams); } + private void updateScrollModeWith(boolean hasExceededMaxLayoutHeight) { + mListView.setOverScrollMode(hasExceededMaxLayoutHeight + ? OVER_SCROLL_ALWAYS + : OVER_SCROLL_NEVER); + } + private void updateColor() { final int menuColorResId = R.color.accessibility_floating_menu_background; getMenuGradientDrawable().setColor(getResources().getColor(menuColorResId)); @@ -726,6 +734,11 @@ public class AccessibilityFloatingMenuView extends FrameLayout layerDrawable.setLayerInset(INDEX_MENU_ITEM, left, 0, right, 0); } + @VisibleForTesting + boolean hasExceededMaxLayoutHeight() { + return calculateActualLayoutHeight() > getMaxLayoutHeight(); + } + @Alignment private int calculateCurrentAlignment() { return mCurrentLayoutParams.x >= ((MIN_WINDOW_X + getMaxWindowX()) / 2) @@ -737,6 +750,10 @@ public class AccessibilityFloatingMenuView extends FrameLayout return mCurrentLayoutParams.y / (float) getMaxWindowY(); } + private int calculateActualLayoutHeight() { + return (mPadding + mIconHeight) * mTargets.size() + mPadding; + } + private @DimenRes int getRadiusResId(@SizeType int sizeType, int itemCount) { return sizeType == SizeType.SMALL ? getSmallSizeResIdWith(itemCount) @@ -760,13 +777,16 @@ public class AccessibilityFloatingMenuView extends FrameLayout return new Rect(0, 0, mScreenWidth - getWindowWidth(), mScreenHeight - getWindowHeight()); } + private int getMaxLayoutHeight() { + return mScreenHeight - mMargin * 2; + } + private int getLayoutWidth() { return mPadding * 2 + mIconWidth; } private int getLayoutHeight() { - return Math.min(mScreenHeight - mMargin * 2, - (mPadding + mIconHeight) * mTargets.size() + mPadding); + return Math.min(getMaxLayoutHeight(), calculateActualLayoutHeight()); } private int getWindowWidth() { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 3d8603409342..179b077a3714 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -20,6 +20,7 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricManager.Authenticators; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityTaskManager; @@ -39,6 +40,7 @@ import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -57,6 +59,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.inject.Inject; @@ -73,16 +76,13 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, private static final String TAG = "AuthController"; private static final boolean DEBUG = true; + private final Handler mHandler = new Handler(Looper.getMainLooper()); private final CommandQueue mCommandQueue; private final StatusBarStateController mStatusBarStateController; private final ActivityTaskManager mActivityTaskManager; @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FaceManager mFaceManager; private final Provider<UdfpsController> mUdfpsControllerFactory; - - @Nullable private final List<FingerprintSensorPropertiesInternal> mFpProps; - @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps; - @Nullable private final List<FingerprintSensorPropertiesInternal> mUdfpsProps; @Nullable private final PointF mFaceAuthSensorLocation; // TODO: These should just be saved from onSaveState @@ -90,7 +90,6 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @VisibleForTesting AuthDialog mCurrentDialog; - private Handler mHandler = new Handler(Looper.getMainLooper()); private WindowManager mWindowManager; @Nullable private UdfpsController mUdfpsController; @@ -98,6 +97,9 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, TaskStackListener mTaskStackListener; @VisibleForTesting IBiometricSysuiReceiver mReceiver; + @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps; + @Nullable private List<FingerprintSensorPropertiesInternal> mFpProps; + @Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps; private class BiometricTaskStackListener extends TaskStackListener { @Override @@ -106,8 +108,31 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } } - @VisibleForTesting - final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @NonNull + private final IFingerprintAuthenticatorsRegisteredCallback + mFingerprintAuthenticatorsRegisteredCallback = + new IFingerprintAuthenticatorsRegisteredCallback.Stub() { + @Override public void onAllAuthenticatorsRegistered( + List<FingerprintSensorPropertiesInternal> sensors) { + if (DEBUG) { + Log.d(TAG, "onFingerprintProvidersAvailable | sensors: " + Arrays.toString( + sensors.toArray())); + } + mFpProps = sensors; + List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>(); + for (FingerprintSensorPropertiesInternal props : mFpProps) { + if (props.isAnyUdfpsType()) { + udfpsProps.add(props); + } + } + mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null; + if (mUdfpsProps != null) { + mUdfpsController = mUdfpsControllerFactory.get(); + } + } + }; + + @VisibleForTesting final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (mCurrentDialog != null @@ -348,19 +373,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mFaceManager = faceManager; mUdfpsControllerFactory = udfpsControllerFactory; - mFpProps = mFingerprintManager != null ? mFingerprintManager.getSensorPropertiesInternal() - : null; mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null; - List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>(); - if (mFpProps != null) { - for (FingerprintSensorPropertiesInternal props : mFpProps) { - if (props.isAnyUdfpsType()) { - udfpsProps.add(props); - } - } - } - mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null; int[] faceAuthLocation = context.getResources().getIntArray( com.android.systemui.R.array.config_face_auth_props); if (faceAuthLocation == null || faceAuthLocation.length < 2) { @@ -383,9 +397,9 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mCommandQueue.addCallback(this); mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected() - && mUdfpsProps != null) { - mUdfpsController = mUdfpsControllerFactory.get(); + if (mFingerprintManager != null) { + mFingerprintManager.addAuthenticatorsRegisteredCallback( + mFingerprintAuthenticatorsRegisteredCallback); } mTaskStackListener = new BiometricTaskStackListener(); @@ -527,7 +541,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, return mFaceManager.hasEnrolledTemplates(userId); } - /** + /** * Whether the passed userId has enrolled UDFPS. */ public boolean isUdfpsEnrolled(int userId) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS b/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS index 8765c9a64b77..947466f3baaf 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/biometrics/OWNERS @@ -1,7 +1,3 @@ set noparent -kchyn@google.com -jaggies@google.com -curtislb@google.com -ilyamaty@google.com -joshmccloskey@google.com +include /services/core/java/com/android/server/biometrics/OWNERS diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 7ebfb7266c11..ee5fb313fff3 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -28,7 +28,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Resources; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.RectF; @@ -55,6 +54,7 @@ import android.view.Surface; import android.view.VelocityTracker; import android.view.View; import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardUpdateMonitor; @@ -108,6 +108,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { @NonNull private final Handler mMainHandler; @NonNull private final FalsingManager mFalsingManager; @NonNull private final PowerManager mPowerManager; + @NonNull private final AccessibilityManager mAccessibilityManager; // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple // sensors, this, in addition to a lot of the code here, will be updated. @VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps; @@ -276,6 +277,13 @@ public class UdfpsController implements DozeReceiver, HbmCallback { private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) -> onTouch(view, event, true); + @SuppressLint("ClickableViewAccessibility") + private final UdfpsView.OnHoverListener mOnHoverListener = (view, event) -> + onTouch(view, event, true); + + private final AccessibilityManager.TouchExplorationStateChangeListener + mTouchExplorationStateChangeListener = enabled -> updateTouchListener(); + /** * @param x coordinate * @param y coordinate @@ -300,6 +308,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { udfpsView.onTouchOutsideView(); break; case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_HOVER_ENTER: // To simplify the lifecycle of the velocity tracker, make sure it's never null // after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP. if (mVelocityTracker == null) { @@ -322,6 +331,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { break; case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_HOVER_MOVE: final int idx = mActivePointerId == -1 ? event.getPointerId(0) : event.findPointerIndex(mActivePointerId); @@ -388,6 +398,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_HOVER_EXIT: mActivePointerId = -1; if (mVelocityTracker != null) { mVelocityTracker.recycle(); @@ -409,10 +420,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { @Inject public UdfpsController(@NonNull Context context, - @Main Resources resources, @NonNull LayoutInflater inflater, @Nullable FingerprintManager fingerprintManager, - WindowManager windowManager, + @NonNull WindowManager windowManager, @NonNull StatusBarStateController statusBarStateController, @Main DelayableExecutor fgExecutor, @NonNull StatusBar statusBar, @@ -421,7 +431,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback { @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor, @NonNull KeyguardViewMediator keyguardViewMediator, @NonNull FalsingManager falsingManager, - @NonNull PowerManager powerManager) { + @NonNull PowerManager powerManager, + @NonNull AccessibilityManager accessibilityManager) { mContext = context; // TODO (b/185124905): inject main handler and vibrator once done prototyping mMainHandler = new Handler(Looper.getMainLooper()); @@ -440,6 +451,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { mKeyguardViewMediator = keyguardViewMediator; mFalsingManager = falsingManager; mPowerManager = powerManager; + mAccessibilityManager = accessibilityManager; mSensorProps = findFirstUdfps(); // At least one UDFPS sensor exists @@ -577,7 +589,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { mView.setAnimationViewController(animation); mWindowManager.addView(mView, computeLayoutParams(animation)); - mView.setOnTouchListener(mOnTouchListener); + mAccessibilityManager.addTouchExplorationStateChangeListener( + mTouchExplorationStateChangeListener); + updateTouchListener(); } catch (RuntimeException e) { Log.e(TAG, "showUdfpsOverlay | failed to add window", e); } @@ -650,7 +664,10 @@ public class UdfpsController implements DozeReceiver, HbmCallback { onFingerUp(); mWindowManager.removeView(mView); mView.setOnTouchListener(null); + mView.setOnHoverListener(null); mView.setAnimationViewController(null); + mAccessibilityManager.removeTouchExplorationStateChangeListener( + mTouchExplorationStateChangeListener); mView = null; } else { Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden"); @@ -758,4 +775,18 @@ public class UdfpsController implements DozeReceiver, HbmCallback { return defaultEffect; } } + + private void updateTouchListener() { + if (mView == null) { + return; + } + + if (mAccessibilityManager.isTouchExplorationEnabled()) { + mView.setOnHoverListener(mOnHoverListener); + mView.setOnTouchListener(null); + } else { + mView.setOnHoverListener(null); + mView.setOnTouchListener(mOnTouchListener); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java index 01d59597197c..58881d9a33f4 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java @@ -16,6 +16,8 @@ package com.android.systemui.classifier; +import static com.android.systemui.classifier.Classifier.BACK_GESTURE; +import static com.android.systemui.classifier.Classifier.GENERIC; import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_SUCCESS; import static com.android.systemui.classifier.FalsingModule.BRIGHT_LINE_GESTURE_CLASSIFERS; @@ -79,6 +81,7 @@ public class BrightLineFalsingManager implements FalsingManager { private final Collection<FalsingClassifier> mClassifiers; private final List<FalsingBeliefListener> mFalsingBeliefListeners = new ArrayList<>(); + private List<FalsingTapListener> mFalsingTapListeners = new ArrayList<>(); private final SessionListener mSessionListener = new SessionListener() { @Override @@ -195,32 +198,26 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public boolean isFalseTouch(@Classifier.InteractionType int interactionType) { mPriorInteractionType = interactionType; - if (skipFalsing()) { + if (skipFalsing(interactionType)) { + mPriorResults = getPassedResult(1); + logDebug("Skipped falsing"); return false; } - final boolean booleanResult; - - if (!mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()) { - final boolean[] localResult = {false}; - mPriorResults = mClassifiers.stream().map(falsingClassifier -> { - FalsingClassifier.Result r = falsingClassifier.classifyGesture( - interactionType, - mHistoryTracker.falseBelief(), - mHistoryTracker.falseConfidence()); - localResult[0] |= r.isFalse(); + final boolean[] localResult = {false}; + mPriorResults = mClassifiers.stream().map(falsingClassifier -> { + FalsingClassifier.Result r = falsingClassifier.classifyGesture( + interactionType, + mHistoryTracker.falseBelief(), + mHistoryTracker.falseConfidence()); + localResult[0] |= r.isFalse(); - return r; - }).collect(Collectors.toList()); - booleanResult = localResult[0]; - } else { - booleanResult = false; - mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1)); - } + return r; + }).collect(Collectors.toList()); - logDebug("False Gesture: " + booleanResult); + logDebug("False Gesture: " + localResult[0]); - return booleanResult; + return localResult[0]; } @Override @@ -234,7 +231,9 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public boolean isFalseTap(@Penalty int penalty) { - if (skipFalsing()) { + if (skipFalsing(GENERIC)) { + mPriorResults = getPassedResult(1); + logDebug("Skipped falsing"); return false; } @@ -263,7 +262,7 @@ public class BrightLineFalsingManager implements FalsingManager { if (!singleTapResult.isFalse()) { if (mDataProvider.isJustUnlockedWithFace()) { // Immediately pass if a face is detected. - mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1)); + mPriorResults = getPassedResult(1); logDebug("False Single Tap: false (face detected)"); return false; } else if (!isFalseDoubleTap()) { @@ -277,9 +276,10 @@ public class BrightLineFalsingManager implements FalsingManager { FalsingClassifier.Result.falsed( 0, getClass().getSimpleName(), "bad history")); logDebug("False Single Tap: true (bad history)"); + mFalsingTapListeners.forEach(FalsingTapListener::onDoubleTapRequired); return true; } else { - mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(0.1)); + mPriorResults = getPassedResult(0.1); logDebug("False Single Tap: false (default)"); return false; } @@ -293,7 +293,9 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public boolean isFalseDoubleTap() { - if (skipFalsing()) { + if (skipFalsing(GENERIC)) { + mPriorResults = getPassedResult(1); + logDebug("Skipped falsing"); return false; } @@ -306,8 +308,12 @@ public class BrightLineFalsingManager implements FalsingManager { return result.isFalse(); } - private boolean skipFalsing() { - return !mKeyguardStateController.isShowing(); + private boolean skipFalsing(@Classifier.InteractionType int interactionType) { + return interactionType == BACK_GESTURE + || !mKeyguardStateController.isShowing() + || mTestHarness + || mDataProvider.isJustUnlockedWithFace() + || mDockManager.isDocked(); } @Override @@ -356,6 +362,16 @@ public class BrightLineFalsingManager implements FalsingManager { } @Override + public void addTapListener(FalsingTapListener listener) { + mFalsingTapListeners.add(listener); + } + + @Override + public void removeTapListener(FalsingTapListener listener) { + mFalsingTapListeners.remove(listener); + } + + @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ipw.println("BRIGHTLINE FALSING MANAGER"); @@ -399,6 +415,10 @@ public class BrightLineFalsingManager implements FalsingManager { mHistoryTracker.removeBeliefListener(mBeliefListener); } + private static Collection<FalsingClassifier.Result> getPassedResult(double confidence) { + return Collections.singleton(FalsingClassifier.Result.passed(confidence)); + } + static void logDebug(String msg) { logDebug(msg, null); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java index 6f70672dbb54..ffdcff2ef2b0 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java @@ -43,6 +43,7 @@ public abstract class Classifier { public static final int UDFPS_AUTHENTICATION = 13; public static final int DISABLED_UDFPS_AFFORDANCE = 14; public static final int QS_SWIPE = 15; + public static final int BACK_GESTURE = 16; @IntDef({ QUICK_SETTINGS, @@ -61,7 +62,8 @@ public abstract class Classifier { BRIGHTNESS_SLIDER, UDFPS_AUTHENTICATION, DISABLED_UDFPS_AFFORDANCE, - QS_SWIPE + QS_SWIPE, + BACK_GESTURE }) @Retention(RetentionPolicy.SOURCE) public @interface InteractionType {} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java index e557773fe295..e8445d40836e 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java @@ -146,4 +146,14 @@ public class FalsingManagerFake implements FalsingManager { public void removeFalsingBeliefListener(FalsingBeliefListener listener) { mFalsingBeliefListeners.remove(listener); } + + @Override + public void addTapListener(FalsingTapListener falsingTapListener) { + + } + + @Override + public void removeTapListener(FalsingTapListener falsingTapListener) { + + } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index 1723291e26f8..6b819fbbbcf1 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -176,6 +176,16 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { } @Override + public void addTapListener(FalsingTapListener listener) { + mInternalFalsingManager.addTapListener(listener); + } + + @Override + public void removeTapListener(FalsingTapListener listener) { + mInternalFalsingManager.removeTapListener(listener); + } + + @Override public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) { mInternalFalsingManager.onProximityEvent(proximityEvent); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index d8ade2bdd21f..41964652ac49 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -376,8 +376,8 @@ public class DozeLog implements Dumpable { case REASON_SENSOR_DOUBLE_TAP: return "doubletap"; case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; case PULSE_REASON_DOCKING: return "docking"; - case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen"; - case REASON_SENSOR_WAKE_UP: return "wakeup"; + case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "reach-wakelockscreen"; + case REASON_SENSOR_WAKE_UP: return "presence-wakeup"; case REASON_SENSOR_TAP: return "tap"; case REASON_SENSOR_UDFPS_LONG_PRESS: return "udfps"; case REASON_SENSOR_QUICK_PICKUP: return "quickPickup"; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 5cea31b5a905..39adabb06d40 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -40,11 +40,9 @@ import android.view.Display; import androidx.annotation.VisibleForTesting; -import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; -import com.android.internal.logging.nano.MetricsProto; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.biometrics.AuthController; import com.android.systemui.plugins.SensorManagerPlugin; @@ -491,10 +489,6 @@ public class DozeSensors { mHandler.post(mWakeLock.wrap(() -> { if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event)); if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { - int subType = (int) event.values[0]; - MetricsLogger.action( - mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE, - subType); UI_EVENT_LOGGER.log(DozeSensorsUiEvent.ACTION_AMBIENT_GESTURE_PICKUP); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index ee559659801b..c45eb3558948 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -24,7 +24,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.hardware.display.AmbientDisplayConfiguration; -import android.metrics.LogMaker; import android.os.SystemClock; import android.os.UserHandle; import android.text.format.Formatter; @@ -33,12 +32,8 @@ import android.util.Log; import android.view.Display; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; -import com.android.internal.logging.UiEventLoggerImpl; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.systemui.Dependency; import com.android.systemui.biometrics.AuthController; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Main; @@ -70,8 +65,6 @@ public class DozeTriggers implements DozeMachine.Part { /** adb shell am broadcast -a com.android.systemui.doze.pulse com.android.systemui */ private static final String PULSE_ACTION = "com.android.systemui.doze.pulse"; - private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl(); - /** * Last value sent by the wake-display sensor. * Assuming that the screen should start on. @@ -99,12 +92,11 @@ public class DozeTriggers implements DozeMachine.Part { private final BroadcastDispatcher mBroadcastDispatcher; private final AuthController mAuthController; private final DelayableExecutor mMainExecutor; + private final UiEventLogger mUiEventLogger; private long mNotificationPulseTime; private boolean mPulsePending; - private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); - /** see {@link #onProximityFar} prox for callback */ private boolean mWantProxSensor; private boolean mWantTouchScreenSensors; @@ -143,7 +135,10 @@ public class DozeTriggers implements DozeMachine.Part { DOZING_UPDATE_AUTH_TRIGGERED(657), @UiEvent(doc = "Dozing updated because quick pickup sensor woke up.") - DOZING_UPDATE_QUICK_PICKUP(708); + DOZING_UPDATE_QUICK_PICKUP(708), + + @UiEvent(doc = "Dozing updated - sensor wakeup timed out (from quick pickup or presence)") + DOZING_UPDATE_WAKE_TIMEOUT(794); private final int mId; @@ -182,7 +177,8 @@ public class DozeTriggers implements DozeMachine.Part { ProximitySensor proximitySensor, ProximitySensor.ProximityCheck proxCheck, DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher, SecureSettings secureSettings, AuthController authController, - @Main DelayableExecutor mainExecutor) { + @Main DelayableExecutor mainExecutor, + UiEventLogger uiEventLogger) { mContext = context; mDozeHost = dozeHost; mConfig = config; @@ -200,6 +196,7 @@ public class DozeTriggers implements DozeMachine.Part { mBroadcastDispatcher = broadcastDispatcher; mAuthController = authController; mMainExecutor = mainExecutor; + mUiEventLogger = uiEventLogger; } @Override @@ -328,11 +325,8 @@ public class DozeTriggers implements DozeMachine.Part { private void gentleWakeUp(int reason) { // Log screen wake up reason (lift/pickup, tap, double-tap) - mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) - .setType(MetricsEvent.TYPE_UPDATE) - .setSubtype(reason)); Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason)) - .ifPresent(UI_EVENT_LOGGER::log); + .ifPresent(mUiEventLogger::log); if (mDozeParameters.getDisplayNeedsBlanking()) { // Let's prepare the display to wake-up by drawing black. // This will cover the hardware wake-up sequence, where the display @@ -401,10 +395,9 @@ public class DozeTriggers implements DozeMachine.Part { } if (state == DozeMachine.State.DOZE) { mMachine.requestState(DozeMachine.State.DOZE_AOD); - // Logs AOD open due to sensor wake up. - mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) - .setType(MetricsEvent.TYPE_OPEN) - .setSubtype(reason)); + // Log sensor triggered + Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason)) + .ifPresent(mUiEventLogger::log); if (isQuickPickup) { // schedule runnable to go back to DOZE @@ -427,10 +420,8 @@ public class DozeTriggers implements DozeMachine.Part { return; } mMachine.requestState(DozeMachine.State.DOZE); - // Logs AOD close due to sensor wake up. - mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) - .setType(MetricsEvent.TYPE_CLOSE) - .setSubtype(reason)); + // log wake timeout + mUiEventLogger.log(DozingUpdateUiEvent.DOZING_UPDATE_WAKE_TIMEOUT); } } } @@ -563,10 +554,8 @@ public class DozeTriggers implements DozeMachine.Part { }, !mDozeParameters.getProxCheckBeforePulse() || performedProxCheck, reason); // Logs request pulse reason on AOD screen. - mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) - .setType(MetricsEvent.TYPE_UPDATE).setSubtype(reason)); Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason)) - .ifPresent(UI_EVENT_LOGGER::log); + .ifPresent(mUiEventLogger::log); } private boolean canPulse() { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index 97803c1cf2fd..666afed41c35 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -70,7 +70,7 @@ public class KeyguardService extends Service { /** * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY */ - private static boolean sEnableRemoteKeyguardAnimation = + static boolean sEnableRemoteKeyguardAnimation = SystemProperties.getBoolean(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, false); private final KeyguardViewMediator mKeyguardViewMediator; @@ -138,6 +138,7 @@ public class KeyguardService extends Service { @Override // Binder interface public void onAnimationCancelled() { + mKeyguardViewMediator.cancelKeyguardExitAnimation(); } }; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt new file mode 100644 index 000000000000..411c328cd310 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ValueAnimator +import android.content.Context +import android.graphics.Matrix +import android.view.RemoteAnimationTarget +import android.view.SyncRtSurfaceTransactionApplier +import androidx.core.math.MathUtils +import com.android.internal.R +import com.android.keyguard.KeyguardViewController +import com.android.systemui.animation.Interpolators +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.policy.KeyguardStateController +import dagger.Lazy +import javax.inject.Inject + +/** + * Starting scale factor for the app/launcher surface behind the keyguard, when it's animating + * in during keyguard exit. + */ +const val SURFACE_BEHIND_START_SCALE_FACTOR = 0.95f + +/** + * How much to translate the surface behind the keyguard at the beginning of the exit animation, + * in terms of percentage of the surface's height. + */ +const val SURFACE_BEHIND_START_TRANSLATION_Y = 0.05f + +/** + * Y coordinate of the pivot point for the scale effect on the surface behind the keyguard. This + * is expressed as percentage of the surface's height, so 0.66f means the surface will scale up + * from the point at (width / 2, height * 0.66). + */ +const val SURFACE_BEHIND_SCALE_PIVOT_Y = 0.66f + +/** + * Dismiss amount at which to fade in the surface behind the keyguard. The surface will then animate + * along with the dismiss amount until [DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD] is reached. + * + * The dismiss amount is the inverse of the notification panel expansion, which decreases as the + * lock screen is swiped away. + */ +const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.1f + +/** + * Dismiss amount at which to complete the keyguard exit animation and hide the keyguard. + * + * The dismiss amount is the inverse of the notification panel expansion, which decreases as the + * lock screen is swiped away. + */ +const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.3f + +/** + * Initiates, controls, and ends the keyguard unlock animation. + * + * The unlock animation transitions between the keyguard (lock screen) and the app/launcher surface + * behind the keyguard. If the user is swiping away the keyguard, this controller will decide when + * to animate in the surface, and synchronize its appearance with the swipe gesture. If the keyguard + * is animating away via a canned animation (due to biometric unlock, tapping a notification, etc.) + * this controller will play a canned animation on the surface as well. + * + * The surface behind the keyguard is manipulated via a RemoteAnimation passed to + * [notifyStartKeyguardExitAnimation] by [KeyguardViewMediator]. + */ +@SysUISingleton +class KeyguardUnlockAnimationController @Inject constructor( + context: Context, + private val keyguardStateController: KeyguardStateController, + private val keyguardViewMediator: Lazy<KeyguardViewMediator>, + private val keyguardViewController: KeyguardViewController +) : KeyguardStateController.Callback { + + /** + * Information used to start, run, and finish a RemoteAnimation on the app or launcher surface + * behind the keyguard. + * + * If we're swiping to unlock, the "animation" is controlled via the gesture, tied to the + * dismiss amounts received in [onKeyguardDismissAmountChanged]. It does not have a fixed + * duration, and it ends when the gesture reaches a certain threshold or is cancelled. + * + * If we're unlocking via biometrics, PIN entry, or from clicking a notification, a canned + * animation is started in [notifyStartKeyguardExitAnimation]. + */ + private var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null + private var surfaceBehindRemoteAnimationTarget: RemoteAnimationTarget? = null + private var surfaceBehindRemoteAnimationStartTime: Long = 0 + + /** + * Alpha value applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the + * app/launcher behind the keyguard. + * + * If we're doing a swipe gesture, we fade in the surface when the swipe passes a certain + * threshold. If we're doing a canned animation, it'll be faded in while a translate/scale + * animation plays. + */ + private var surfaceBehindAlpha = 1f + private var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f) + + /** + * Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the + * app/launcher behind the keyguard. + * + * This is used during the unlock animation/swipe gesture to scale and translate the surface. + */ + private val surfaceBehindMatrix = Matrix() + + /** + * Animator that animates in the surface behind the keyguard. This is used to play a canned + * animation on the surface, if we're not doing a swipe gesture. + */ + private val surfaceBehindEntryAnimator = ValueAnimator.ofFloat(0f, 1f) + + /** Rounded corner radius to apply to the surface behind the keyguard. */ + private var roundedCornerRadius = 0f + + init { + surfaceBehindAlphaAnimator.duration = 150 + surfaceBehindAlphaAnimator.interpolator = Interpolators.ALPHA_IN + surfaceBehindAlphaAnimator.addUpdateListener { valueAnimator: ValueAnimator -> + surfaceBehindAlpha = valueAnimator.animatedValue as Float + updateSurfaceBehindAppearAmount() + } + surfaceBehindAlphaAnimator.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + // If the surface alpha is 0f, it's no longer visible so we can safely be done with + // the animation. + if (surfaceBehindAlpha == 0f) { + keyguardViewMediator.get().finishSurfaceBehindRemoteAnimation() + } + } + }) + + surfaceBehindEntryAnimator.duration = 450 + surfaceBehindEntryAnimator.interpolator = Interpolators.DECELERATE_QUINT + surfaceBehindEntryAnimator.addUpdateListener { valueAnimator: ValueAnimator -> + surfaceBehindAlpha = valueAnimator.animatedValue as Float + setSurfaceBehindAppearAmount(valueAnimator.animatedValue as Float) + } + surfaceBehindEntryAnimator.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished() + } + }) + + // Listen for changes in the dismiss amount. + keyguardStateController.addCallback(this) + + roundedCornerRadius = + context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat() + } + + /** + * Called from [KeyguardViewMediator] to tell us that the RemoteAnimation on the surface behind + * the keyguard has started successfully. We can use these parameters to directly manipulate the + * surface for the unlock gesture/animation. + * + * When we're done with it, we'll call [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation] + * to end the RemoteAnimation. + * + * [requestedShowSurfaceBehindKeyguard] denotes whether the exit animation started because of a + * call to [KeyguardViewMediator.showSurfaceBehindKeyguard], as happens during a swipe gesture, + * as opposed to the keyguard hiding. + */ + fun notifyStartKeyguardExitAnimation( + target: RemoteAnimationTarget, + startTime: Long, + requestedShowSurfaceBehindKeyguard: Boolean + ) { + + if (surfaceTransactionApplier == null) { + surfaceTransactionApplier = SyncRtSurfaceTransactionApplier( + keyguardViewController.viewRootImpl.view) + } + + surfaceBehindRemoteAnimationTarget = target + surfaceBehindRemoteAnimationStartTime = startTime + + // If the surface behind wasn't made visible during a swipe, we'll do a canned animation + // to animate it in. Otherwise, the swipe touch events will continue animating it. + if (!requestedShowSurfaceBehindKeyguard) { + keyguardViewController.hide(startTime, 350) + surfaceBehindEntryAnimator.start() + } + } + + fun notifyCancelKeyguardExitAnimation() { + surfaceBehindRemoteAnimationTarget = null + } + + fun notifyFinishedKeyguardExitAnimation() { + surfaceBehindRemoteAnimationTarget = null + } + + fun hideKeyguardViewAfterRemoteAnimation() { + keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350) + } + + /** + * Scales in and translates up the surface behind the keyguard. This is used during unlock + * animations and swipe gestures to animate the surface's entry (and exit, if the swipe is + * cancelled). + */ + private fun setSurfaceBehindAppearAmount(amount: Float) { + if (surfaceBehindRemoteAnimationTarget == null) { + return + } + + val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.height() + val scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR + + (1f - SURFACE_BEHIND_START_SCALE_FACTOR) * + MathUtils.clamp(amount, 0f, 1f)) + + // Scale up from a point at the center-bottom of the surface. + surfaceBehindMatrix.setScale( + scaleFactor, + scaleFactor, + surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.width() / 2f, + surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y) + + // Translate up from the bottom. + surfaceBehindMatrix.postTranslate(0f, + surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount)) + + // If we're snapping the keyguard back, immediately begin fading it out. + val animationAlpha = + if (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount + else surfaceBehindAlpha + + val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder( + surfaceBehindRemoteAnimationTarget!!.leash) + .withMatrix(surfaceBehindMatrix) + .withCornerRadius(roundedCornerRadius) + .withAlpha(animationAlpha) + .build() + surfaceTransactionApplier!!.scheduleApply(params) + } + + /** + * Sets the appearance amount of the surface behind the keyguard, according to the current + * keyguard dismiss amount and the method of dismissal. + */ + private fun updateSurfaceBehindAppearAmount() { + if (surfaceBehindRemoteAnimationTarget == null) { + return + } + + // For fling animations, we want to animate the surface in over the full distance. If we're + // dismissing the keyguard via a swipe gesture (or cancelling the swipe gesture), we want to + // bring in the surface behind over a relatively short swipe distance (~15%), to keep the + // interaction tight. + if (keyguardStateController.isFlingingToDismissKeyguard) { + setSurfaceBehindAppearAmount(keyguardStateController.dismissAmount) + } else if (keyguardStateController.isDismissingFromSwipe || + keyguardStateController.isSnappingKeyguardBackAfterSwipe) { + val totalSwipeDistanceToDismiss = + (DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD - DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD) + val swipedDistanceSoFar: Float = + keyguardStateController.dismissAmount - DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD + val progress = swipedDistanceSoFar / totalSwipeDistanceToDismiss + setSurfaceBehindAppearAmount(progress) + } + } + + override fun onKeyguardDismissAmountChanged() { + if (!KeyguardService.sEnableRemoteKeyguardAnimation) { + return + } + + val dismissAmount = keyguardStateController.dismissAmount + + // Hide the keyguard if we're fully dismissed, or if we're swiping to dismiss and have + // crossed the threshold to finish the dismissal. + val reachedHideKeyguardThreshold = (dismissAmount >= 1f || + (keyguardStateController.isDismissingFromSwipe && + // Don't hide if we're flinging during a swipe, since we need to finish + // animating it out. This will be called again after the fling ends. + !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture && + dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)) + + if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD && + !keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) { + // We passed the threshold, and we're not yet showing the surface behind the keyguard. + // Animate it in. + keyguardViewMediator.get().showSurfaceBehindKeyguard() + fadeInSurfaceBehind() + } else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD && + keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) { + // We're no longer past the threshold but we are showing the surface. Animate it out. + keyguardViewMediator.get().hideSurfaceBehindKeyguard() + fadeOutSurfaceBehind() + } else if (keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe && + reachedHideKeyguardThreshold) { + keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished() + } + + if (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() || + keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) { + updateSurfaceBehindAppearAmount() + } + } + + private fun fadeInSurfaceBehind() { + surfaceBehindAlphaAnimator.cancel() + surfaceBehindAlphaAnimator.start() + } + + private fun fadeOutSurfaceBehind() { + surfaceBehindAlphaAnimator.cancel() + surfaceBehindAlphaAnimator.reverse() + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 70459df3dafb..48f9a58d7d1a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -17,6 +17,7 @@ package com.android.systemui.keyguard; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; +import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; @@ -72,7 +73,6 @@ import android.util.SparseIntArray; import android.view.IRemoteAnimationFinishedCallback; import android.view.RemoteAnimationTarget; import android.view.SyncRtSurfaceTransactionApplier; -import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -109,6 +109,7 @@ import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.DeviceConfigProxy; import java.io.FileDescriptor; @@ -195,6 +196,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, private static final int NOTIFY_SCREEN_TURNED_OFF = 16; private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 17; private static final int SYSTEM_READY = 18; + private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19; /** * The default amount of time we stay awake (used for all key input) @@ -350,7 +352,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, private int mUnlockSoundId; private int mTrustedSoundId; private int mLockSoundStreamId; - /** * The animation used for hiding keyguard. This is used to fetch the animation timings if * WindowManager is not providing us with them. @@ -400,6 +401,29 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, private IKeyguardDrawnCallback mDrawnCallback; private CharSequence mCustomMessage; + /** + * Whether the RemoteAnimation on the app/launcher surface behind the keyguard is 'running'. + * Note that this does not necessarily mean the surface is currently in motion - we may be + * 'animating' it along with the user's finger during a swipe to unlock gesture, a gesture that + * can be paused or reversed. + */ + private boolean mSurfaceBehindRemoteAnimationRunning; + + /** + * Whether we've asked to make the app/launcher surface behind the keyguard visible, via a call + * to {@link android.app.IActivityTaskManager#keyguardGoingAway(int)}. + * + * Since that's an IPC, this doesn't necessarily mean the remote animation has started yet. + * {@link #mSurfaceBehindRemoteAnimationRunning} will be true if the call completed and the + * animation is now running. + */ + private boolean mSurfaceBehindRemoteAnimationRequested = false; + + /** + * Callback to run to end the RemoteAnimation on the app/launcher surface behind the keyguard. + */ + private IRemoteAnimationFinishedCallback mSurfaceBehindRemoteAnimationFinishedCallback; + private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = new DeviceConfig.OnPropertiesChangedListener() { @Override @@ -735,6 +759,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, private DeviceConfigProxy mDeviceConfig; private DozeParameters mDozeParameters; + private final KeyguardStateController mKeyguardStateController; + private final Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy; + /** * Injected constructor. See {@link KeyguardModule}. */ @@ -752,7 +779,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, NavigationModeController navigationModeController, KeyguardDisplayManager keyguardDisplayManager, DozeParameters dozeParameters, - StatusBarStateController statusBarStateController) { + StatusBarStateController statusBarStateController, + KeyguardStateController keyguardStateController, + Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationControllerLazy) { super(context); mFalsingCollector = falsingCollector; mLockPatternUtils = lockPatternUtils; @@ -780,6 +809,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, })); mDozeParameters = dozeParameters; statusBarStateController.addCallback(this); + + mKeyguardStateController = keyguardStateController; + mKeyguardUnlockAnimationControllerLazy = keyguardUnlockAnimationControllerLazy; } public void userActivity() { @@ -1732,6 +1764,12 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, mFalsingCollector.onSuccessfulUnlock(); Trace.endSection(); break; + case CANCEL_KEYGUARD_EXIT_ANIM: + Trace.beginSection( + "KeyguardViewMediator#handleMessage CANCEL_KEYGUARD_EXIT_ANIM"); + handleCancelKeyguardExitAnimation(); + Trace.endSection(); + break; case KEYGUARD_DONE_PENDING_TIMEOUT: Trace.beginSection("KeyguardViewMediator#handleMessage" + " KEYGUARD_DONE_PENDING_TIMEOUT"); @@ -1943,7 +1981,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, int flags = 0; if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock() - || (mWakeAndUnlocking && !mPulsing)) { + || (mWakeAndUnlocking && !mPulsing) + || isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) { flags |= WindowManagerPolicyConstants .KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; } @@ -1952,7 +1991,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE; } if (mKeyguardViewControllerLazy.get().isUnlockWithWallpaper()) { - flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; + flags |= KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; } if (mKeyguardViewControllerLazy.get().shouldSubtleWindowAnimationsForUnlock()) { flags |= WindowManagerPolicyConstants @@ -2033,8 +2072,13 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, + " fadeoutDuration=" + fadeoutDuration); synchronized (KeyguardViewMediator.this) { - if (!mHiding) { - // Tell ActivityManager that we canceled the keyguardExitAnimation. + // Tell ActivityManager that we canceled the keyguard animation if + // handleStartKeyguardExitAnimation was called but we're not hiding the keyguard, unless + // we're animating the surface behind the keyguard and will be hiding the keyguard + // shortly. + if (!mHiding + && !mSurfaceBehindRemoteAnimationRequested + && !mKeyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture()) { setShowingLocked(mShowing, true /* force */); return; } @@ -2056,61 +2100,184 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, playSounds(false); } - setShowingLocked(false); - mWakeAndUnlocking = false; - mDismissCallbackRegistry.notifyDismissSucceeded(); - mKeyguardViewControllerLazy.get().hide(startTime, fadeoutDuration); - - // TODO(bc-animation): When remote animation is enabled for keyguard exit animation, - // apps, wallpapers and finishedCallback are set to non-null. nonApps is not yet - // supported, so it's always null. - mContext.getMainExecutor().execute(() -> { - if (finishedCallback == null) { + if (KeyguardService.sEnableRemoteKeyguardAnimation) { + mSurfaceBehindRemoteAnimationFinishedCallback = finishedCallback; + mSurfaceBehindRemoteAnimationRunning = true; + + if (apps != null && apps.length > 0) { + // Pass the surface and metadata to the unlock animation controller. + mKeyguardUnlockAnimationControllerLazy.get().notifyStartKeyguardExitAnimation( + apps[0], startTime, mSurfaceBehindRemoteAnimationRequested); + } else { + // We weren't given any surfaces to animate, so just finish. + onKeyguardExitRemoteAnimationFinished(); return; } + } else { + setShowingLocked(false); + mWakeAndUnlocking = false; + mDismissCallbackRegistry.notifyDismissSucceeded(); + mKeyguardViewControllerLazy.get().hide(startTime, fadeoutDuration); + + // TODO(bc-animation): When remote animation is enabled for keyguard exit animation, + // apps, wallpapers and finishedCallback are set to non-null. nonApps is not yet + // supported, so it's always null. + mContext.getMainExecutor().execute(() -> { + if (finishedCallback == null) { + return; + } - // TODO(bc-unlock): Sample animation, just to apply alpha animation on the app. - final SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier( - mKeyguardViewControllerLazy.get().getViewRootImpl().getView()); - final RemoteAnimationTarget primary = apps[0]; - ValueAnimator anim = ValueAnimator.ofFloat(0, 1); - anim.setDuration(400 /* duration */); - anim.setInterpolator(Interpolators.LINEAR); - anim.addUpdateListener((ValueAnimator animation) -> { - SurfaceParams params = new SurfaceParams.Builder(primary.leash) - .withAlpha(animation.getAnimatedFraction()) - .build(); - applier.scheduleApply(params); - }); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - try { - finishedCallback.onAnimationFinished(); - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException"); + // TODO(bc-unlock): Sample animation, just to apply alpha animation on the app. + final SyncRtSurfaceTransactionApplier applier = + new SyncRtSurfaceTransactionApplier( + mKeyguardViewControllerLazy.get().getViewRootImpl().getView()); + final RemoteAnimationTarget primary = apps[0]; + ValueAnimator anim = ValueAnimator.ofFloat(0, 1); + anim.setDuration(400 /* duration */); + anim.setInterpolator(Interpolators.LINEAR); + anim.addUpdateListener((ValueAnimator animation) -> { + SyncRtSurfaceTransactionApplier.SurfaceParams params = + new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder( + primary.leash) + .withAlpha(animation.getAnimatedFraction()) + .build(); + applier.scheduleApply(params); + }); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + try { + finishedCallback.onAnimationFinished(); + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException"); + } } - } - @Override - public void onAnimationCancel(Animator animation) { - try { - finishedCallback.onAnimationFinished(); - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException"); + @Override + public void onAnimationCancel(Animator animation) { + try { + finishedCallback.onAnimationFinished(); + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException"); + } } - } + }); + anim.start(); }); - anim.start(); - }); - resetKeyguardDonePendingLocked(); - mHideAnimationRun = false; - adjustStatusBarLocked(); - sendUserPresentBroadcast(); + resetKeyguardDonePendingLocked(); + mHideAnimationRun = false; + adjustStatusBarLocked(); + sendUserPresentBroadcast(); + } } + Trace.endSection(); } + /** + * Whether we're currently animating between the keyguard and the app/launcher surface behind + * it, or will be shortly (which happens if we started a fling to dismiss the keyguard). + */ + public boolean isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe() { + return mSurfaceBehindRemoteAnimationRunning + || mKeyguardStateController.isFlingingToDismissKeyguard(); + } + + /** + * Called if the keyguard exit animation has been cancelled and we should return to the + * keyguard. + * + * This can happen due to the system cancelling the RemoteAnimation (due to a timeout), or the + * user cancelling the unlock swipe gesture. + */ + private void handleCancelKeyguardExitAnimation() { + hideSurfaceBehindKeyguard(); + mKeyguardUnlockAnimationControllerLazy.get().notifyCancelKeyguardExitAnimation(); + } + + /** + * Called when we're done running the keyguard exit animation. + * + * This will call {@link #mSurfaceBehindRemoteAnimationFinishedCallback} to let WM know that + * we're done with the RemoteAnimation, actually hide the keyguard, and clean up state related + * to the keyguard exit animation. + */ + public void onKeyguardExitRemoteAnimationFinished() { + if (!mSurfaceBehindRemoteAnimationRunning && !mSurfaceBehindRemoteAnimationRequested) { + return; + } + + // Block the panel from expanding, in case we were doing a swipe to dismiss gesture. + mKeyguardViewControllerLazy.get().blockPanelExpansionFromCurrentTouch(); + final boolean wasShowing = mShowing; + setShowingLocked(false); + + mWakeAndUnlocking = false; + mDismissCallbackRegistry.notifyDismissSucceeded(); + + if (mKeyguardStateController.isDismissingFromSwipe() || !wasShowing) { + mKeyguardUnlockAnimationControllerLazy.get().hideKeyguardViewAfterRemoteAnimation(); + } + + finishSurfaceBehindRemoteAnimation(); + + resetKeyguardDonePendingLocked(); + mHideAnimationRun = false; + adjustStatusBarLocked(); + sendUserPresentBroadcast(); + mSurfaceBehindRemoteAnimationRequested = false; + mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation(); + } + + /** + * Tells the ActivityTaskManager that the keyguard is planning to go away, so that it makes the + * surface behind the keyguard visible and calls {@link #handleStartKeyguardExitAnimation} with + * the parameters needed to animate the surface. + */ + public void showSurfaceBehindKeyguard() { + mSurfaceBehindRemoteAnimationRequested = true; + + try { + ActivityTaskManager.getService().keyguardGoingAway( + WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS + | WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER); + } catch (RemoteException e) { + mSurfaceBehindRemoteAnimationRequested = false; + e.printStackTrace(); + } + } + + /** Hides the surface behind the keyguard by re-showing the keyguard/activity lock screen. */ + public void hideSurfaceBehindKeyguard() { + mSurfaceBehindRemoteAnimationRequested = false; + + if (mShowing) { + setShowingLocked(true, true); + } + } + + /** + * Whether we have requested to show the surface behind the keyguard, even if it's not yet + * visible due to IPC delay. + */ + public boolean requestedShowSurfaceBehindKeyguard() { + return mSurfaceBehindRemoteAnimationRequested; + } + + /** If it's running, finishes the RemoteAnimation on the surface behind the keyguard. */ + public void finishSurfaceBehindRemoteAnimation() { + mSurfaceBehindRemoteAnimationRunning = false; + + if (mSurfaceBehindRemoteAnimationFinishedCallback != null) { + try { + mSurfaceBehindRemoteAnimationFinishedCallback.onAnimationFinished(); + mSurfaceBehindRemoteAnimationFinishedCallback = null; + } catch (RemoteException e) { + e.printStackTrace(); + } + } + } + private void adjustStatusBarLocked() { adjustStatusBarLocked(false /* forceHideHomeRecentsButtons */, false /* forceClearFlags */); @@ -2346,6 +2513,19 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, Trace.endSection(); } + /** + * Cancel the keyguard exit animation, usually because we were swiping to unlock and the swipe + * gesture was cancelled. + * + * This will re-show the keyguard and animate out the app/launcher surface behind the keyguard. + */ + public void cancelKeyguardExitAnimation() { + Trace.beginSection("KeyguardViewMediator#cancelKeyguardExitAnimation"); + Message msg = mHandler.obtainMessage(CANCEL_KEYGUARD_EXIT_ANIM); + mHandler.sendMessage(msg); + Trace.endSection(); + } + public void onShortPowerPressedGoHome() { // do nothing } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index a747edd0580a..ecee1b508ce0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -42,6 +42,7 @@ import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.FaceAuthScreenBrightnessController; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -49,6 +50,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardLiftController; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.settings.GlobalSettings; @@ -92,7 +94,9 @@ public class KeyguardModule { NavigationModeController navigationModeController, KeyguardDisplayManager keyguardDisplayManager, DozeParameters dozeParameters, - StatusBarStateController statusBarStateController) { + StatusBarStateController statusBarStateController, + KeyguardStateController keyguardStateController, + Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController) { return new KeyguardViewMediator( context, falsingCollector, @@ -109,7 +113,9 @@ public class KeyguardModule { navigationModeController, keyguardDisplayManager, dozeParameters, - statusBarStateController + statusBarStateController, + keyguardStateController, + keyguardUnlockAnimationController ); } diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt index 6fb86504ec32..b668e881230d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt @@ -17,6 +17,7 @@ package com.android.systemui.media import android.view.View +import android.view.ViewGroup import com.android.systemui.dagger.SysUISingleton import com.android.systemui.media.dagger.MediaModule.KEYGUARD import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -29,8 +30,8 @@ import javax.inject.Inject import javax.inject.Named /** - * A class that controls the media notifications on the lock screen, handles its visibility and - * is responsible for the embedding of he media experience. + * Controls the media notifications on the lock screen, handles its visibility and placement - + * switches media player positioning between split pane container vs single pane container */ @SysUISingleton class KeyguardMediaController @Inject constructor( @@ -43,46 +44,120 @@ class KeyguardMediaController @Inject constructor( init { statusBarStateController.addCallback(object : StatusBarStateController.StateListener { override fun onStateChanged(newState: Int) { - updateVisibility() + refreshMediaPosition() + } + + override fun onDozingChanged(isDozing: Boolean) { + if (!isDozing) { + mediaHost.visible = true + refreshMediaPosition() + } } }) + + // First let's set the desired state that we want for this host + mediaHost.expansion = MediaHostState.COLLAPSED + mediaHost.showsOnlyActiveMedia = true + mediaHost.falsingProtectionNeeded = true + + // Let's now initialize this view, which also creates the host view for us. + mediaHost.init(MediaHierarchyManager.LOCATION_LOCKSCREEN) } var visibilityChangedListener: ((Boolean) -> Unit)? = null - var view: MediaHeaderView? = null + + /** + * single pane media container placed at the top of the notifications list + */ + var singlePaneContainer: MediaHeaderView? = null private set + private var splitShadeContainer: ViewGroup? = null + private var useSplitShadeContainer: () -> Boolean = { false } /** - * Attach this controller to a media view, initializing its state + * Attaches media container in single pane mode, situated at the top of the notifications list */ - fun attach(mediaView: MediaHeaderView) { - view = mediaView - // First let's set the desired state that we want for this host - mediaHost.addVisibilityChangeListener { updateVisibility() } - mediaHost.expansion = 0.0f - mediaHost.showsOnlyActiveMedia = true - mediaHost.falsingProtectionNeeded = true + fun attachSinglePaneContainer(mediaView: MediaHeaderView?) { + singlePaneContainer = mediaView - // Let's now initialize this view, which also creates the host view for us. - mediaHost.init(MediaHierarchyManager.LOCATION_LOCKSCREEN) - mediaView.setContentView(mediaHost.hostView) + // Required to show it for the first time, afterwards visibility is managed automatically + mediaHost.visible = true + mediaHost.addVisibilityChangeListener { visible -> + refreshMediaPosition() + if (visible) { + mediaHost.hostView.layoutParams.apply { + height = ViewGroup.LayoutParams.WRAP_CONTENT + width = ViewGroup.LayoutParams.MATCH_PARENT + } + } + } + refreshMediaPosition() + } - // Ensure the visibility is correct - updateVisibility() + /** + * Attaches media container in split shade mode, situated to the left of notifications + */ + fun attachSplitShadeContainer(container: ViewGroup, useContainer: () -> Boolean) { + splitShadeContainer = container + useSplitShadeContainer = useContainer } - private fun updateVisibility() { + fun refreshMediaPosition() { val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD || statusBarStateController.state == StatusBarState.FULLSCREEN_USER_SWITCHER) + // mediaHost.visible required for proper animations handling val shouldBeVisible = mediaHost.visible && !bypassController.bypassEnabled && keyguardOrUserSwitcher && notifLockscreenUserManager.shouldShowLockscreenNotifications() - val previousVisibility = view?.visibility ?: View.GONE - val newVisibility = if (shouldBeVisible) View.VISIBLE else View.GONE + if (shouldBeVisible) { + showMediaPlayer() + } else { + hideMediaPlayer() + } + } + + private fun showMediaPlayer() { + if (useSplitShadeContainer()) { + showMediaPlayer( + activeContainer = splitShadeContainer, + inactiveContainer = singlePaneContainer) + } else { + showMediaPlayer( + activeContainer = singlePaneContainer, + inactiveContainer = splitShadeContainer) + } + } + + private fun showMediaPlayer(activeContainer: ViewGroup?, inactiveContainer: ViewGroup?) { + if (inactiveContainer?.childCount == 1) { + inactiveContainer.removeAllViews() + } + // might be called a few times for the same view, no need to add hostView again + if (activeContainer?.childCount == 0) { + // Detach the hostView from its parent view if exists + mediaHost.hostView.parent ?.let { + (it as? ViewGroup)?.removeView(mediaHost.hostView) + } + activeContainer.addView(mediaHost.hostView) + } + setVisibility(activeContainer, View.VISIBLE) + setVisibility(inactiveContainer, View.GONE) + } + + private fun hideMediaPlayer() { + if (useSplitShadeContainer()) { + setVisibility(splitShadeContainer, View.GONE) + } else { + setVisibility(singlePaneContainer, View.GONE) + } + } + + private fun setVisibility(view: ViewGroup?, newVisibility: Int) { + val previousVisibility = view?.visibility view?.visibility = newVisibility if (previousVisibility != newVisibility) { - visibilityChangedListener?.invoke(shouldBeVisible) + visibilityChangedListener?.invoke(newVisibility == View.VISIBLE) } } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index 2ecd40578d68..d87142f195dc 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -1,6 +1,5 @@ package com.android.systemui.media -import android.animation.ArgbEvaluator import android.app.smartspace.SmartspaceTarget import android.content.Context import android.content.Intent @@ -116,8 +115,7 @@ class MediaCarouselController @Inject constructor( private var needsReordering: Boolean = false private var keysNeedRemoval = mutableSetOf<String>() private var bgColor = getBackgroundColor() - private var fgColor = com.android.settingslib.Utils.getColorAttr(context, - com.android.internal.R.attr.textColorPrimary).defaultColor + private var fgColor = getForegroundColor() private var isRtl: Boolean = false set(value) { if (value != field) { @@ -319,7 +317,7 @@ class MediaCarouselController @Inject constructor( val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp) - newRecs.bindRecommendation(data, bgColor, { v -> removePlayer(key) }) + newRecs.bindRecommendation(data, bgColor) MediaPlayerData.addMediaPlayer(key, newRecs) updatePlayerToState(newRecs, noAnimation = true) reorderAllPlayers() @@ -348,20 +346,18 @@ class MediaCarouselController @Inject constructor( if (dismissMediaData) { // Inform the media manager of a potentially late dismissal - mediaManager.dismissMediaData(key, 0L) + mediaManager.dismissMediaData(key, 0L /* delaye */) } if (dismissRecommendation) { // Inform the media manager of a potentially late dismissal - mediaManager.dismissSmartspaceRecommendation() + mediaManager.dismissSmartspaceRecommendation(0L /* delay */) } } } private fun recreatePlayers() { bgColor = getBackgroundColor() - - fgColor = com.android.settingslib.Utils.getColorAttr(context, - com.android.internal.R.attr.textColorPrimary).defaultColor + fgColor = getForegroundColor() pageIndicator.tintList = ColorStateList.valueOf(fgColor) MediaPlayerData.mediaData().forEach { (key, data) -> @@ -371,12 +367,12 @@ class MediaCarouselController @Inject constructor( } private fun getBackgroundColor(): Int { - val themeAccent = com.android.settingslib.Utils.getColorAttr(context, - com.android.internal.R.attr.colorAccent).defaultColor - val themeBackground = com.android.settingslib.Utils.getColorAttr(context, - com.android.internal.R.attr.colorBackground).defaultColor - // Simulate transparency - cannot be actually transparent because of lockscreen - return ArgbEvaluator().evaluate(0.25f, themeBackground, themeAccent) as Int + return context.getColor(android.R.color.system_accent2_50) + } + + private fun getForegroundColor(): Int { + return com.android.settingslib.Utils.getColorAttr(context, + com.android.internal.R.attr.textColorPrimary).defaultColor } private fun updatePageIndicator() { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 94cb2dcedc38..96ae2cd37740 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -25,7 +25,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.ColorStateList; -import android.graphics.Outline; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; @@ -33,10 +32,8 @@ import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.PlaybackState; import android.os.Bundle; -import android.os.SystemProperties; import android.util.Log; import android.view.View; -import android.view.ViewOutlineProvider; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; @@ -46,7 +43,6 @@ import androidx.annotation.Nullable; import androidx.annotation.UiThread; import androidx.constraintlayout.widget.ConstraintSet; -import com.android.settingslib.Utils; import com.android.settingslib.widget.AdaptiveIcon; import com.android.systemui.R; import com.android.systemui.animation.ActivityLaunchAnimator; @@ -75,11 +71,6 @@ public class MediaControlPanel { private static final String EXTRAS_MEDIA_SOURCE_PACKAGE_NAME = "package_name"; private static final int MEDIA_RECOMMENDATION_MAX_NUM = 4; - private final boolean mShowAppName = SystemProperties.getBoolean( - "persist.sysui.qs_media_show_app_name", false); - private final boolean mShowDeviceName = SystemProperties.getBoolean( - "persist.sysui.qs_media_show_device_name", false); - private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS); // Button IDs for QS controls @@ -106,10 +97,8 @@ public class MediaControlPanel { private KeyguardDismissUtil mKeyguardDismissUtil; private Lazy<MediaDataManager> mMediaDataManagerLazy; private int mBackgroundColor; + private int mDevicePadding; private int mAlbumArtSize; - private int mAlbumArtRadius; - // This will provide the corners for the album art. - private final ViewOutlineProvider mViewOutlineProvider; private final MediaOutputDialogFactory mMediaOutputDialogFactory; /** @@ -133,13 +122,6 @@ public class MediaControlPanel { mKeyguardDismissUtil = keyguardDismissUtil; mMediaOutputDialogFactory = mediaOutputDialogFactory; loadDimens(); - - mViewOutlineProvider = new ViewOutlineProvider() { - @Override - public void getOutline(View view, Outline outline) { - outline.setRoundRect(0, 0, mAlbumArtSize, mAlbumArtSize, mAlbumArtRadius); - } - }; } public void onDestroy() { @@ -151,9 +133,9 @@ public class MediaControlPanel { } private void loadDimens() { - mAlbumArtRadius = mContext.getResources().getDimensionPixelSize( - Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius)); mAlbumArtSize = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_album_size); + mDevicePadding = mContext.getResources() + .getDimensionPixelSize(R.dimen.qs_media_album_device_padding); } /** @@ -211,10 +193,6 @@ public class MediaControlPanel { mPlayerViewHolder = vh; TransitionLayout player = vh.getPlayer(); - ImageView albumView = vh.getAlbumView(); - albumView.setOutlineProvider(mViewOutlineProvider); - albumView.setClipToOutline(true); - mSeekBarObserver = new SeekBarObserver(vh); mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver); mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar()); @@ -242,6 +220,21 @@ public class MediaControlPanel { TransitionLayout recommendations = vh.getRecommendations(); mMediaViewController.attach(recommendations, MediaViewController.TYPE.RECOMMENDATION); + + mRecommendationViewHolder.getRecommendations().setOnLongClickListener(v -> { + if (!mMediaViewController.isGutsVisible()) { + mMediaViewController.openGuts(); + return true; + } else { + return false; + } + }); + mRecommendationViewHolder.getCancel().setOnClickListener(v -> { + closeGuts(); + }); + mRecommendationViewHolder.getSettings().setOnClickListener(v -> { + mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */); + }); } /** Bind this player view based on the data given. */ @@ -282,10 +275,19 @@ public class MediaControlPanel { boolean hasArtwork = data.getArtwork() != null; if (hasArtwork) { Drawable artwork = scaleDrawable(data.getArtwork()); + albumView.setPadding(0, 0, 0, 0); albumView.setImageDrawable(artwork); + } else { + Drawable deviceIcon; + if (data.getDevice() != null && data.getDevice().getIcon() != null) { + deviceIcon = data.getDevice().getIcon().getConstantState().newDrawable().mutate(); + } else { + deviceIcon = getContext().getDrawable(R.drawable.ic_headphone); + } + deviceIcon.setTintList(ColorStateList.valueOf(mBackgroundColor)); + albumView.setPadding(mDevicePadding, mDevicePadding, mDevicePadding, mDevicePadding); + albumView.setImageDrawable(deviceIcon); } - setVisibleAndAlpha(collapsedSet, R.id.album_art, hasArtwork); - setVisibleAndAlpha(expandedSet, R.id.album_art, hasArtwork); // App icon ImageView appIcon = mPlayerViewHolder.getAppIcon(); @@ -300,13 +302,6 @@ public class MediaControlPanel { TextView titleText = mPlayerViewHolder.getTitleText(); titleText.setText(data.getSong()); - // App title - TextView appName = mPlayerViewHolder.getAppName(); - appName.setText(data.getApp()); - appName.setVisibility(mShowAppName ? View.VISIBLE : View.GONE); - setVisibleAndAlpha(collapsedSet, R.id.app_name, mShowAppName); - setVisibleAndAlpha(expandedSet, R.id.app_name, mShowAppName); - // Artist name TextView artistText = mPlayerViewHolder.getArtistText(); artistText.setText(data.getArtist()); @@ -318,10 +313,6 @@ public class MediaControlPanel { mPlayerViewHolder.getSeamless().setOnClickListener(v -> { mMediaOutputDialogFactory.create(data.getPackageName(), true); }); - TextView mDeviceName = mPlayerViewHolder.getSeamlessText(); - mDeviceName.setVisibility(mShowDeviceName ? View.VISIBLE : View.GONE); - setVisibleAndAlpha(collapsedSet, R.id.media_seamless_text, mShowDeviceName); - setVisibleAndAlpha(expandedSet, R.id.media_seamless_text, mShowDeviceName); ImageView iconView = mPlayerViewHolder.getSeamlessIcon(); TextView deviceName = mPlayerViewHolder.getSeamlessText(); @@ -391,8 +382,12 @@ public class MediaControlPanel { // Hide any unused buttons for (; i < ACTION_IDS.length; i++) { - setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /*visible */); setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */); + setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /* visible */); + } + // If no expanded buttons, set the first view as INVISIBLE so z remains constant + if (actionIcons.size() == 0) { + expandedSet.setVisibility(ACTION_IDS[0], ConstraintSet.INVISIBLE); } // Seek Bar @@ -461,10 +456,7 @@ public class MediaControlPanel { } /** Bind this recommendation view based on the data given. */ - public void bindRecommendation( - @NonNull SmartspaceTarget target, - @NonNull int backgroundColor, - @Nullable View.OnClickListener callback) { + public void bindRecommendation(@NonNull SmartspaceTarget target, @NonNull int backgroundColor) { if (mRecommendationViewHolder == null) { return; } @@ -520,8 +512,13 @@ public class MediaControlPanel { mediaCoverImageView.setImageIcon(recommendation.getIcon()); // Set up the click listener if applicable. - setSmartspaceOnClickListener(mediaCoverImageView, recommendation, - target.getSmartspaceTargetId(), callback); + setSmartspaceRecItemOnClickListener( + mediaCoverImageView, + recommendation, + target.getSmartspaceTargetId(), + view -> mMediaDataManagerLazy + .get() + .dismissSmartspaceRecommendation(0L /* delay */)); setVisibleAndAlpha(expandedSet, mediaCoverItemsResIds.get(i), true); setVisibleAndAlpha(expandedSet, mediaLogoItemsResIds.get(i), true); @@ -529,6 +526,16 @@ public class MediaControlPanel { setVisibleAndAlpha(collapsedSet, mediaLogoItemsResIds.get(i), true); } + // Set up long press to show guts setting panel. + mRecommendationViewHolder.getDismiss().setOnClickListener(v -> { + closeGuts(); + mKeyguardDismissUtil.executeWhenUnlocked(() -> { + mMediaDataManagerLazy.get().dismissSmartspaceRecommendation( + MediaViewController.GUTS_ANIMATION_DURATION + 100L); + return true; + }, true /* requiresShadeOpen */); + }); + mController = null; mMediaViewController.refreshState(); } @@ -613,7 +620,7 @@ public class MediaControlPanel { set.setAlpha(actionId, visible ? 1.0f : 0.0f); } - private void setSmartspaceOnClickListener( + private void setSmartspaceRecItemOnClickListener( @NonNull View view, @NonNull SmartspaceAction action, @NonNull String targetId, diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt index 6ef29d694873..6f0c88710461 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt @@ -31,7 +31,7 @@ data class MediaData( */ val app: String?, /** - * Icon shown on player, close to app name. + * App icon shown on player. */ val appIcon: Icon?, /** diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt index 5f73ae0814c7..9163044c2d73 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt @@ -16,6 +16,7 @@ package com.android.systemui.media +import android.app.smartspace.SmartspaceAction import android.app.smartspace.SmartspaceTarget import android.os.SystemProperties import android.util.Log @@ -121,6 +122,12 @@ class MediaDataFilter @Inject constructor( } // If no recent media, continue with smartspace update + if (isMediaRecommendationEmpty(data)) { + Log.d(TAG, "Empty media recommendations. Skip showing the card") + return + } + + // Proceed only if the Smartspace recommendation is not empty. listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data) } } @@ -191,7 +198,7 @@ class MediaDataFilter @Inject constructor( mediaDataManager.setTimedOut(it, timedOut = true, forceUpdate = true) } if (hasSmartspace) { - mediaDataManager.dismissSmartspaceRecommendation() + mediaDataManager.dismissSmartspaceRecommendation(0L /* delay */) } } @@ -214,4 +221,10 @@ class MediaDataFilter @Inject constructor( * Remove a listener that was registered with addListener */ fun removeListener(listener: MediaDataManager.Listener) = _listeners.remove(listener) + + /** Check if the Smartspace sends an empty update. */ + private fun isMediaRecommendationEmpty(data: SmartspaceTarget): Boolean { + val mediaRecommendationList: List<SmartspaceAction> = data.getIconGrid() + return mediaRecommendationList == null || mediaRecommendationList.isEmpty() + } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 78071769043c..138c4222831f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -115,12 +115,15 @@ class MediaDataManager( // UI surface label for subscribing Smartspace updates. @JvmField val SMARTSPACE_UI_SURFACE_LABEL = "media_data_manager" + + // Maximum number of actions allowed in compact view + @JvmField + val MAX_COMPACT_ACTIONS = 3 } private val themeText = com.android.settingslib.Utils.getColorAttr(context, com.android.internal.R.attr.textColorPrimary).defaultColor - private val bgColor = com.android.settingslib.Utils.getColorAttr(context, - com.android.internal.R.attr.colorBackground).defaultColor + private val bgColor = context.getColor(android.R.color.system_accent2_50) // Internal listeners are part of the internal pipeline. External listeners (those registered // with [MediaDeviceManager.addListener]) receive events after they have propagated through @@ -429,12 +432,13 @@ class MediaDataManager( * This will make the recommendation view to not be shown anymore during this headphone * connection session. */ - fun dismissSmartspaceRecommendation() { + fun dismissSmartspaceRecommendation(delay: Long) { Log.d(TAG, "Dismissing Smartspace media target") // Do not set smartspaceMediaTarget to null. So the instance is preserved during the entire // headphone connection, and will ONLY be set to null when headphones are disconnected. smartspaceMediaTarget?.let { - notifySmartspaceMediaDataRemoved(it.smartspaceTargetId) + foregroundExecutor.executeDelayed( + { notifySmartspaceMediaDataRemoved(it.smartspaceTargetId) }, delay) } } @@ -548,8 +552,12 @@ class MediaDataManager( // Control buttons val actionIcons: MutableList<MediaAction> = ArrayList() val actions = notif.actions - val actionsToShowCollapsed = notif.extras.getIntArray( + var actionsToShowCollapsed = notif.extras.getIntArray( Notification.EXTRA_COMPACT_ACTIONS)?.toMutableList() ?: mutableListOf<Int>() + if (actionsToShowCollapsed.size > MAX_COMPACT_ACTIONS) { + Log.e(TAG, "Too many compact actions for $key, limiting to first $MAX_COMPACT_ACTIONS") + actionsToShowCollapsed = actionsToShowCollapsed.subList(0, MAX_COMPACT_ACTIONS) + } // TODO: b/153736623 look into creating actions when this isn't a media style notification if (actions != null) { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt index 8c12a305992e..28e46409e5c6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt @@ -25,6 +25,8 @@ class MediaHost constructor( private val tmpLocationOnScreen: IntArray = intArrayOf(0, 0) + private var inited: Boolean = false + /** * Get the current bounds on the screen. This makes sure the state is fresh and up to date */ @@ -84,6 +86,11 @@ class MediaHost constructor( * transitions. */ fun init(@MediaLocation location: Int) { + if (inited) { + return + } + inited = true + this.location = location hostView = mediaHierarchyManager.register(this) hostView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener { @@ -264,15 +271,20 @@ class MediaHost constructor( */ interface MediaHostState { + companion object { + const val EXPANDED: Float = 1.0f + const val COLLAPSED: Float = 0.0f + } + /** - * The last measurement input that this state was measured with. Infers with and height of + * The last measurement input that this state was measured with. Infers width and height of * the players. */ var measurementInput: MeasurementInput? /** - * The expansion of the player, 0 for fully collapsed (up to 3 actions), 1 for fully expanded - * (up to 5 actions.) + * The expansion of the player, [COLLAPSED] for fully collapsed (up to 3 actions), + * [EXPANDED] for fully expanded (up to 5 actions). */ var expansion: Float diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt index e848e2fa0c08..f78556f18492 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt @@ -252,16 +252,30 @@ class MediaViewController @Inject constructor( * [TransitionViewState]. */ private fun setGutsViewState(viewState: TransitionViewState) { - PlayerViewHolder.controlsIds.forEach { id -> - viewState.widgetStates.get(id)?.let { state -> - // Make sure to use the unmodified state if guts are not visible - state.alpha = if (isGutsVisible) 0f else state.alpha - state.gone = if (isGutsVisible) true else state.gone + if (type == TYPE.PLAYER) { + PlayerViewHolder.controlsIds.forEach { id -> + viewState.widgetStates.get(id)?.let { state -> + // Make sure to use the unmodified state if guts are not visible. + state.alpha = if (isGutsVisible) 0f else state.alpha + state.gone = if (isGutsVisible) true else state.gone + } + } + PlayerViewHolder.gutsIds.forEach { id -> + viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f + viewState.widgetStates.get(id)?.gone = !isGutsVisible + } + } else { + RecommendationViewHolder.controlsIds.forEach { id -> + viewState.widgetStates.get(id)?.let { state -> + // Make sure to use the unmodified state if guts are not visible. + state.alpha = if (isGutsVisible) 0f else state.alpha + state.gone = if (isGutsVisible) true else state.gone + } + } + RecommendationViewHolder.gutsIds.forEach { id -> + viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f + viewState.widgetStates.get(id)?.gone = !isGutsVisible } - } - PlayerViewHolder.gutsIds.forEach { id -> - viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f - viewState.widgetStates.get(id)?.gone = !isGutsVisible } } diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt index 16327bd9064a..08d87261ae80 100644 --- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt @@ -35,7 +35,6 @@ class PlayerViewHolder private constructor(itemView: View) { // Player information val appIcon = itemView.requireViewById<ImageView>(R.id.icon) - val appName = itemView.requireViewById<TextView>(R.id.app_name) val albumView = itemView.requireViewById<ImageView>(R.id.album_art) val titleText = itemView.requireViewById<TextView>(R.id.header_title) val artistText = itemView.requireViewById<TextView>(R.id.header_artist) @@ -120,6 +119,7 @@ class PlayerViewHolder private constructor(itemView: View) { R.id.header_title, R.id.header_artist, R.id.media_seamless, + R.id.media_seamless_fallback, R.id.notification_media_progress_time, R.id.media_progress_bar, R.id.action0, @@ -130,7 +130,6 @@ class PlayerViewHolder private constructor(itemView: View) { R.id.icon ) val gutsIds = setOf( - R.id.media_text, R.id.remove_text, R.id.cancel, R.id.dismiss, diff --git a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt index ac201a804e38..02150c4a8562 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt @@ -28,6 +28,8 @@ import com.android.systemui.util.animation.TransitionLayout class RecommendationViewHolder private constructor(itemView: View) { val recommendations = itemView as TransitionLayout + + // Recommendation screen val mediaCoverItems = listOf<ImageView>( itemView.requireViewById(R.id.media_cover1), itemView.requireViewById(R.id.media_cover2), @@ -49,16 +51,26 @@ class RecommendationViewHolder private constructor(itemView: View) { R.id.media_logo3, R.id.media_logo4) + // Settings/Guts screen + val cancel = itemView.requireViewById<View>(R.id.cancel) + val dismiss = itemView.requireViewById<ViewGroup>(R.id.dismiss) + val dismissLabel = dismiss.getChildAt(0) + val settings = itemView.requireViewById<View>(R.id.settings) + init { (recommendations.background as IlluminationDrawable).let { background -> mediaCoverItems.forEach { background.registerLightSource(it) } mediaLogoItems.forEach { background.registerLightSource(it) } + background.registerLightSource(cancel) + background.registerLightSource(dismiss) + background.registerLightSource(dismissLabel) + background.registerLightSource(settings) } } companion object { /** - * Creates a PlayerViewHolder. + * Creates a RecommendationViewHolder. * * @param inflater LayoutInflater to use to inflate the layout. * @param parent Parent of inflated view. @@ -76,5 +88,25 @@ class RecommendationViewHolder private constructor(itemView: View) { itemView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE return RecommendationViewHolder(itemView) } + + // Res Ids for the control components on the recommendation view. + val controlsIds = setOf( + R.id.media_cover1, + R.id.media_cover2, + R.id.media_cover3, + R.id.media_cover4, + R.id.media_logo1, + R.id.media_logo2, + R.id.media_logo3, + R.id.media_logo4 + ) + + // Res Ids for the components on the guts panel. + val gutsIds = setOf( + R.id.remove_text, + R.id.cancel, + R.id.dismiss, + R.id.settings + ) } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt index d789501ffdef..f17ad6f09128 100644 --- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt @@ -78,6 +78,7 @@ class SeekBarObserver(private val holder: PlayerViewHolder) : Observer<SeekBarVi fun setVerticalPadding(padding: Int) { val leftPadding = holder.seekBar.paddingLeft val rightPadding = holder.seekBar.paddingRight - holder.seekBar.setPadding(leftPadding, padding, rightPadding, padding) + val bottomPadding = holder.seekBar.paddingBottom + holder.seekBar.setPadding(leftPadding, padding, rightPadding, bottomPadding) } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index 01c80f6d33fe..0ed4d861c712 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -83,7 +83,6 @@ import com.android.systemui.navigationbar.gestural.RegionSamplingHelper; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsOnboarding; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.SysUiStatsLog; @@ -113,7 +112,6 @@ public class NavigationBarView extends FrameLayout implements private final RegionSamplingHelper mRegionSamplingHelper; private final int mNavColorSampleMargin; private final SysUiState mSysUiFlagContainer; - private final PluginManager mPluginManager; View mCurrentView = null; private View mVertical; @@ -316,7 +314,6 @@ public class NavigationBarView extends FrameLayout implements boolean isGesturalMode = isGesturalMode(mNavBarMode); mSysUiFlagContainer = Dependency.get(SysUiState.class); - mPluginManager = Dependency.get(PluginManager.class); // Set up the context group of buttons mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container); final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher, @@ -366,8 +363,8 @@ public class NavigationBarView extends FrameLayout implements mNavColorSampleMargin = getResources() .getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin); - mEdgeBackGestureHandler = new EdgeBackGestureHandler(context, mOverviewProxyService, - mSysUiFlagContainer, mPluginManager, this::updateStates); + mEdgeBackGestureHandler = Dependency.get(EdgeBackGestureHandler.class); + mEdgeBackGestureHandler.setStateChangeCallback(this::updateStates); mRegionSamplingHelper = new RegionSamplingHelper(this, new RegionSamplingHelper.SamplingCallback() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index 806ea4fa147d..fc615deb1db6 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -15,6 +15,8 @@ */ package com.android.systemui.navigationbar.gestural; +import static com.android.systemui.classifier.Classifier.BACK_GESTURE; + import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; @@ -27,8 +29,6 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; -import android.hardware.display.DisplayManager; -import android.hardware.display.DisplayManager.DisplayListener; import android.hardware.input.InputManager; import android.os.Looper; import android.os.RemoteException; @@ -41,6 +41,7 @@ import android.util.TypedValue; import android.view.Choreographer; import android.view.Display; import android.view.ISystemGestureExclusionListener; +import android.view.IWindowManager; import android.view.InputDevice; import android.view.InputEvent; import android.view.InputMonitor; @@ -50,18 +51,19 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.ViewConfiguration; import android.view.WindowManager; -import android.view.WindowManagerGlobal; import android.view.WindowMetrics; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.policy.GestureNavigationSettingsObserver; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SystemUIFactory; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.model.SysUiState; import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.navigationbar.NavigationModeController; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.NavigationEdgeBackPlugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.recents.OverviewProxyService; @@ -85,9 +87,12 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Executor; +import javax.inject.Inject; + /** * Utility class to handle edge swipes for back gesture */ +@SysUISingleton public class EdgeBackGestureHandler extends CurrentUserTracker implements PluginListener<NavigationEdgeBackPlugin>, ProtoTraceable<SystemUiTraceProto> { @@ -164,9 +169,15 @@ public class EdgeBackGestureHandler extends CurrentUserTracker private final Context mContext; private final OverviewProxyService mOverviewProxyService; private final SysUiState mSysUiState; - private final Runnable mStateChangeCallback; + private Runnable mStateChangeCallback; private final PluginManager mPluginManager; + private final ProtoTracer mProtoTracer; + private final NavigationModeController mNavigationModeController; + private final ViewConfiguration mViewConfiguration; + private final WindowManager mWindowManager; + private final IWindowManager mWindowManagerService; + private final FalsingManager mFalsingManager; // Activities which should not trigger Back gesture. private final List<ComponentName> mGestureBlockingActivities = new ArrayList<>(); @@ -237,6 +248,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker new NavigationEdgeBackPlugin.BackCallback() { @Override public void triggerBack() { + // Notify FalsingManager that an intentional gesture has occurred. + // TODO(b/186519446): use a different method than isFalseTouch + mFalsingManager.isFalseTouch(BACK_GESTURE); boolean sendDown = sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK); boolean sendUp = sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK); if (DEBUG_MISSING_GESTURE) { @@ -267,16 +281,26 @@ public class EdgeBackGestureHandler extends CurrentUserTracker } }; + @Inject public EdgeBackGestureHandler(Context context, OverviewProxyService overviewProxyService, - SysUiState sysUiState, PluginManager pluginManager, Runnable stateChangeCallback) { - super(Dependency.get(BroadcastDispatcher.class)); + SysUiState sysUiState, PluginManager pluginManager, @Main Executor executor, + BroadcastDispatcher broadcastDispatcher, ProtoTracer protoTracer, + NavigationModeController navigationModeController, ViewConfiguration viewConfiguration, + WindowManager windowManager, IWindowManager windowManagerService, + FalsingManager falsingManager) { + super(broadcastDispatcher); mContext = context; mDisplayId = context.getDisplayId(); - mMainExecutor = context.getMainExecutor(); + mMainExecutor = executor; mOverviewProxyService = overviewProxyService; mSysUiState = sysUiState; mPluginManager = pluginManager; - mStateChangeCallback = stateChangeCallback; + mProtoTracer = protoTracer; + mNavigationModeController = navigationModeController; + mViewConfiguration = viewConfiguration; + mWindowManager = windowManager; + mWindowManagerService = windowManagerService; + mFalsingManager = falsingManager; ComponentName recentsComponentName = ComponentName.unflattenFromString( context.getString(com.android.internal.R.string.config_recentsComponentName)); if (recentsComponentName != null) { @@ -309,9 +333,12 @@ public class EdgeBackGestureHandler extends CurrentUserTracker updateCurrentUserResources(); } + public void setStateChangeCallback(Runnable callback) { + mStateChangeCallback = callback; + } + public void updateCurrentUserResources() { - Resources res = Dependency.get(NavigationModeController.class).getCurrentUserContext() - .getResources(); + Resources res = mNavigationModeController.getCurrentUserContext().getResources(); mEdgeWidthLeft = mGestureNavigationSettingsObserver.getLeftSensitivity(res); mEdgeWidthRight = mGestureNavigationSettingsObserver.getRightSensitivity(res); mIsBackGestureAllowed = @@ -336,7 +363,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker // TODO(b/130352502) Tune this value and extract into a constant final float backGestureSlop = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.BACK_GESTURE_SLOP_MULTIPLIER, 0.75f); - mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop() * backGestureSlop; + mTouchSlop = mViewConfiguration.getScaledTouchSlop() * backGestureSlop; } private void onNavigationSettingsChanged() { @@ -358,7 +385,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker */ public void onNavBarAttached() { mIsAttached = true; - Dependency.get(ProtoTracer.class).add(this); + mProtoTracer.add(this); mOverviewProxyService.addCallback(mQuickSwitchListener); mSysUiState.addCallback(mSysUiStateCallback); updateIsEnabled(); @@ -370,7 +397,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker */ public void onNavBarDetached() { mIsAttached = false; - Dependency.get(ProtoTracer.class).remove(this); + mProtoTracer.remove(this); mOverviewProxyService.removeCallback(mQuickSwitchListener); mSysUiState.removeCallback(mSysUiStateCallback); updateIsEnabled(); @@ -424,9 +451,8 @@ public class EdgeBackGestureHandler extends CurrentUserTracker DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener); try { - WindowManagerGlobal.getWindowManagerService() - .unregisterSystemGestureExclusionListener( - mGestureExclusionListener, mDisplayId); + mWindowManagerService.unregisterSystemGestureExclusionListener( + mGestureExclusionListener, mDisplayId); } catch (RemoteException | IllegalArgumentException e) { Log.e(TAG, "Failed to unregister window manager callbacks", e); } @@ -439,13 +465,11 @@ public class EdgeBackGestureHandler extends CurrentUserTracker } TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener); DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, - runnable -> (mContext.getMainThreadHandler()).post(runnable), - mOnPropertiesChangedListener); + mMainExecutor::execute, mOnPropertiesChangedListener); try { - WindowManagerGlobal.getWindowManagerService() - .registerSystemGestureExclusionListener( - mGestureExclusionListener, mDisplayId); + mWindowManagerService.registerSystemGestureExclusionListener( + mGestureExclusionListener, mDisplayId); } catch (RemoteException | IllegalArgumentException e) { Log.e(TAG, "Failed to register window manager callbacks", e); } @@ -801,7 +825,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker } } - Dependency.get(ProtoTracer.class).scheduleFrameUpdate(); + mProtoTracer.scheduleFrameUpdate(); } private void updateDisabledForQuickstep(Configuration newConfig) { @@ -822,8 +846,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker } private void updateDisplaySize() { - WindowMetrics metrics = mContext.getSystemService(WindowManager.class) - .getMaximumWindowMetrics(); + WindowMetrics metrics = mWindowManager.getMaximumWindowMetrics(); Rect bounds = metrics.getBounds(); mDisplaySize.set(bounds.width(), bounds.height()); if (DEBUG_MISSING_GESTURE) { diff --git a/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java b/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java index 68a829ca2e38..0efef02cd191 100644 --- a/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java +++ b/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java @@ -42,7 +42,7 @@ import java.util.Set; /** Helper functions to handle notifications in People Tiles. */ public class NotificationHelper { private static final boolean DEBUG = PeopleSpaceUtils.DEBUG; - private static final String TAG = "PeopleNotificationHelper"; + private static final String TAG = "PeopleNotifHelper"; /** Returns the notification with highest priority to be shown in People Tiles. */ public static NotificationEntry getHighestPriorityNotification( @@ -209,5 +209,30 @@ public class NotificationHelper { } return null; } + + /** Returns whether {@code notification} is a group conversation. */ + private static boolean isGroupConversation(Notification notification) { + return notification.extras.getBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION, false); + } + + /** + * Returns {@code message}'s sender's name if {@code notification} is from a group conversation. + */ + public static CharSequence getSenderIfGroupConversation(Notification notification, + Notification.MessagingStyle.Message message) { + if (!isGroupConversation(notification)) { + if (DEBUG) { + Log.d(TAG, "Notification is not from a group conversation, not checking sender."); + } + return null; + } + Person person = message.getSenderPerson(); + if (person == null) { + if (DEBUG) Log.d(TAG, "Notification from group conversation doesn't include sender."); + return null; + } + if (DEBUG) Log.d(TAG, "Returning sender from group conversation notification."); + return person.getName(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java index eefe5ca93793..99a17ffbe77a 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java @@ -18,6 +18,7 @@ package com.android.systemui.people; import static com.android.systemui.people.NotificationHelper.getContactUri; import static com.android.systemui.people.NotificationHelper.getMessagingStyleMessages; +import static com.android.systemui.people.NotificationHelper.getSenderIfGroupConversation; import static com.android.systemui.people.NotificationHelper.hasReadContactsPermission; import static com.android.systemui.people.NotificationHelper.isMissedCall; import static com.android.systemui.people.NotificationHelper.shouldMatchNotificationByUri; @@ -233,6 +234,7 @@ public class PeopleSpaceUtils { // Reset notification content. .setNotificationKey(null) .setNotificationContent(null) + .setNotificationSender(null) .setNotificationDataUri(null) .setMessagesCount(0) // Reset missed calls category. @@ -245,9 +247,9 @@ public class PeopleSpaceUtils { * {@code messagesCount}. */ public static PeopleSpaceTile augmentTileFromNotification(Context context, PeopleSpaceTile tile, - NotificationEntry notificationEntry, int messagesCount) { + PeopleTileKey key, NotificationEntry notificationEntry, int messagesCount) { if (notificationEntry == null || notificationEntry.getSbn().getNotification() == null) { - if (DEBUG) Log.d(TAG, "Notification is null"); + if (DEBUG) Log.d(TAG, "Tile key: " + key.toString() + ". Notification is null"); return removeNotificationFields(tile); } Notification notification = notificationEntry.getSbn().getNotification(); @@ -256,7 +258,7 @@ public class PeopleSpaceUtils { getMessagingStyleMessages(notification); if (!isMissedCall && ArrayUtils.isEmpty(messages)) { - if (DEBUG) Log.d(TAG, "Notification has no content"); + if (DEBUG) Log.d(TAG, "Tile key: " + key.toString() + ". Notification has no content"); return removeNotificationFields(tile); } @@ -268,13 +270,18 @@ public class PeopleSpaceUtils { CharSequence content = (isMissedCall && !hasMessageText) ? context.getString(R.string.missed_call) : message.getText(); Uri dataUri = message != null ? message.getDataUri() : null; - if (DEBUG) Log.d(TAG, "Notification message has text: " + hasMessageText); + if (DEBUG) { + Log.d(TAG, "Tile key: " + key.toString() + ". Notification message has text: " + + hasMessageText); + } + CharSequence sender = getSenderIfGroupConversation(notification, message); return tile .toBuilder() .setNotificationKey(notificationEntry.getSbn().getKey()) .setNotificationCategory(notification.category) .setNotificationContent(content) + .setNotificationSender(sender) .setNotificationDataUri(dataUri) .setMessagesCount(messagesCount) .build(); @@ -459,7 +466,7 @@ public class PeopleSpaceUtils { } if (DEBUG) { Log.d(TAG, "Widget: " + appWidgetId + ", " + tile.getUserName() + ", " - + tile.getPackageName()); + + tile.getPackageName() + ". Updating app widget view."); } RemoteViews views = new PeopleTileViewHelper(context, tile, appWidgetId, options).getViews(); @@ -472,7 +479,9 @@ public class PeopleSpaceUtils { public static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager, Context context, int appWidgetId, PeopleSpaceTile tile) { if (tile == null) { - Log.d(TAG, "Tile is null, skipping storage and update."); + if (DEBUG) { + Log.w(TAG, "Widget: " + appWidgetId + "Tile is null, skipping storage and update."); + } return; } Bundle options = AppWidgetOptionsHelper.setPeopleTile(appWidgetManager, appWidgetId, tile); @@ -483,7 +492,10 @@ public class PeopleSpaceUtils { public static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager, Context context, int appWidgetId, Optional<PeopleSpaceTile> optionalTile) { if (!optionalTile.isPresent()) { - Log.d(TAG, "Tile is null, skipping storage and update."); + if (DEBUG) { + Log.w(TAG, "Widget: " + appWidgetId + + "Optional tile is not present, skipping storage and update."); + } return; } updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, optionalTile.get()); diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java index bc9a45b3db62..d4ddc6546a19 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java @@ -59,6 +59,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.people.widget.LaunchConversationActivity; import com.android.systemui.people.widget.PeopleSpaceWidgetProvider; +import com.android.systemui.people.widget.PeopleTileKey; import java.text.NumberFormat; import java.time.Duration; @@ -148,6 +149,8 @@ public class PeopleTileViewHelper { * content, then birthdays, then the most recent status, and finally last interaction. */ private RemoteViews getViewForTile() { + PeopleTileKey key = new PeopleTileKey(mTile); + if (DEBUG) Log.d(TAG, "Creating view for tile key: " + key.toString()); if (Objects.equals(mTile.getNotificationCategory(), CATEGORY_MISSED_CALL)) { if (DEBUG) Log.d(TAG, "Create missed call view"); return createMissedCallRemoteViews(); @@ -179,7 +182,7 @@ public class PeopleTileViewHelper { return createLastInteractionRemoteViews(); } - private void setMaxLines(RemoteViews views) { + private void setMaxLines(RemoteViews views, boolean showSender) { int textSize = mLayoutSize == LAYOUT_LARGE ? getSizeInDp( R.dimen.content_text_size_for_medium) : getSizeInDp(R.dimen.content_text_size_for_medium); @@ -187,6 +190,9 @@ public class PeopleTileViewHelper { int notificationContentHeight = getContentHeightForLayout(lineHeight); int maxAdaptiveLines = Math.floorDiv(notificationContentHeight, lineHeight); int maxLines = Math.max(MIN_CONTENT_MAX_LINES, maxAdaptiveLines); + + // Save a line for sender's name, if present. + if (showSender) maxLines--; views.setInt(R.id.text_content, "setMaxLines", maxLines); } @@ -350,7 +356,7 @@ public class PeopleTileViewHelper { RemoteViews views = getViewForContentLayout(); views.setViewVisibility(R.id.predefined_icon, View.VISIBLE); views.setViewVisibility(R.id.messages_count, View.GONE); - setMaxLines(views); + setMaxLines(views, false); views.setTextViewText(R.id.text_content, mTile.getNotificationContent()); views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_phone_missed); return views; @@ -358,6 +364,7 @@ public class PeopleTileViewHelper { private RemoteViews createNotificationRemoteViews() { RemoteViews views = getViewForContentLayout(); + CharSequence sender = mTile.getNotificationSender(); Uri image = mTile.getNotificationDataUri(); if (image != null) { // TODO: Use NotificationInlineImageCache @@ -366,7 +373,7 @@ public class PeopleTileViewHelper { views.setViewVisibility(R.id.text_content, View.GONE); views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_photo_camera); } else { - setMaxLines(views); + setMaxLines(views, !TextUtils.isEmpty(sender)); CharSequence content = mTile.getNotificationContent(); views = setPunctuationRemoteViewsFields(views, content); views.setColorAttr(R.id.text_content, "setTextColor", android.R.attr.textColorPrimary); @@ -382,9 +389,12 @@ public class PeopleTileViewHelper { views.setViewVisibility(R.id.predefined_icon, View.GONE); } } - // TODO: Set subtext as Group Sender name once storing the name in PeopleSpaceTile and - // subtract 1 from maxLines when present. - views.setViewVisibility(R.id.subtext, View.GONE); + if (!TextUtils.isEmpty(sender)) { + views.setViewVisibility(R.id.subtext, View.VISIBLE); + views.setTextViewText(R.id.subtext, sender); + } else { + views.setViewVisibility(R.id.subtext, View.GONE); + } return views; } @@ -414,7 +424,7 @@ public class PeopleTileViewHelper { } views.setViewVisibility(R.id.predefined_icon, View.VISIBLE); views.setViewVisibility(R.id.messages_count, View.GONE); - setMaxLines(views); + setMaxLines(views, false); // Secondary text color for statuses. views.setColorAttr(R.id.text_content, "setTextColor", android.R.attr.textColorSecondary); views.setTextViewText(R.id.text_content, statusText); diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java b/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java index 7254eec71d07..73c43ebfdaf0 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java @@ -41,7 +41,7 @@ public class AppWidgetOptionsHelper { PeopleSpaceTile tile) { Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId); if (tile == null) { - if (DEBUG) Log.d(TAG, "Requested to store null tile"); + if (DEBUG) Log.w(TAG, "Requested to store null tile"); return options; } options.putParcelable(OPTIONS_PEOPLE_TILE, tile); diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java index f11c1bdc6bfb..64a6509ea0aa 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java @@ -236,7 +236,7 @@ public class PeopleSpaceWidgetManager { @Nullable public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key) { if (!key.isValid()) { - Log.e(TAG, "PeopleTileKey invalid: " + key); + Log.e(TAG, "PeopleTileKey invalid: " + key.toString()); return null; } @@ -267,7 +267,14 @@ public class PeopleSpaceWidgetManager { */ public void updateWidgetsWithNotificationChanged(StatusBarNotification sbn, PeopleSpaceUtils.NotificationAction notificationAction) { - if (DEBUG) Log.d(TAG, "updateWidgetsWithNotificationChanged called"); + if (DEBUG) { + Log.d(TAG, "updateWidgetsWithNotificationChanged called"); + if (notificationAction == PeopleSpaceUtils.NotificationAction.POSTED) { + Log.d(TAG, "Notification posted, key: " + sbn.getKey()); + } else { + Log.d(TAG, "Notification removed, key: " + sbn.getKey()); + } + } if (mIsForTesting) { updateWidgetsWithNotificationChangedInBackground(sbn, notificationAction); return; @@ -282,7 +289,7 @@ public class PeopleSpaceWidgetManager { PeopleTileKey key = new PeopleTileKey( sbn.getShortcutId(), sbn.getUser().getIdentifier(), sbn.getPackageName()); if (!key.isValid()) { - Log.d(TAG, "Invalid key from sbn"); + Log.d(TAG, "Sbn doesn't contain valid PeopleTileKey: " + key.toString()); return; } int[] widgetIds = mAppWidgetManager.getAppWidgetIds( @@ -309,8 +316,12 @@ public class PeopleSpaceWidgetManager { /** Updates {@code widgetIdsToUpdate} with {@code action}. */ private void updateWidgetIdsBasedOnNotifications(Set<String> widgetIdsToUpdate) { - Log.d(TAG, "Fetching grouped notifications"); + if (widgetIdsToUpdate.isEmpty()) { + if (DEBUG) Log.d(TAG, "No widgets to update, returning."); + return; + } try { + if (DEBUG) Log.d(TAG, "Fetching grouped notifications"); Map<PeopleTileKey, Set<NotificationEntry>> groupedNotifications = getGroupedConversationNotifications(); @@ -331,14 +342,15 @@ public class PeopleSpaceWidgetManager { * Augments {@code tile} based on notifications returned from {@code notificationEntryManager}. */ public PeopleSpaceTile augmentTileFromNotificationEntryManager(PeopleSpaceTile tile) { - Log.d(TAG, "Augmenting tile from NotificationEntryManager widget: " + tile.getId()); + PeopleTileKey key = new PeopleTileKey(tile); + Log.d(TAG, "Augmenting tile from NotificationEntryManager widget: " + key.toString()); Map<PeopleTileKey, Set<NotificationEntry>> notifications = getGroupedConversationNotifications(); String contactUri = null; if (tile.getContactUri() != null) { contactUri = tile.getContactUri().toString(); } - return augmentTileFromNotifications(tile, contactUri, notifications); + return augmentTileFromNotifications(tile, key, contactUri, notifications); } /** Returns active and pending notifications grouped by {@link PeopleTileKey}. */ @@ -367,9 +379,9 @@ public class PeopleSpaceWidgetManager { } /** Augments {@code tile} based on {@code notifications}, matching {@code contactUri}. */ - public PeopleSpaceTile augmentTileFromNotifications(PeopleSpaceTile tile, String contactUri, - Map<PeopleTileKey, Set<NotificationEntry>> notifications) { - if (DEBUG) Log.d(TAG, "Augmenting tile from notifications. Tile id: " + tile.getId()); + public PeopleSpaceTile augmentTileFromNotifications(PeopleSpaceTile tile, PeopleTileKey key, + String contactUri, Map<PeopleTileKey, Set<NotificationEntry>> notifications) { + if (DEBUG) Log.d(TAG, "Augmenting tile from notifications. Tile key: " + key.toString()); boolean hasReadContactsPermission = mPackageManager.checkPermission(READ_CONTACTS, tile.getPackageName()) == PackageManager.PERMISSION_GRANTED; @@ -384,13 +396,12 @@ public class PeopleSpaceWidgetManager { } } - PeopleTileKey key = new PeopleTileKey(tile); Set<NotificationEntry> allNotifications = notifications.get(key); if (allNotifications == null) { allNotifications = new HashSet<>(); } if (allNotifications.isEmpty() && notificationsByUri.isEmpty()) { - if (DEBUG) Log.d(TAG, "No existing notifications for tile: " + key); + if (DEBUG) Log.d(TAG, "No existing notifications for tile: " + key.toString()); return removeNotificationFields(tile); } @@ -402,22 +413,28 @@ public class PeopleSpaceWidgetManager { NotificationEntry highestPriority = getHighestPriorityNotification(allNotifications); if (DEBUG) Log.d(TAG, "Augmenting tile from notification, key: " + key.toString()); - return augmentTileFromNotification(mContext, tile, highestPriority, messagesCount); + return augmentTileFromNotification(mContext, tile, key, highestPriority, messagesCount); } /** Returns an augmented tile for an existing widget. */ @Nullable public Optional<PeopleSpaceTile> getAugmentedTileForExistingWidget(int widgetId, Map<PeopleTileKey, Set<NotificationEntry>> notifications) { - Log.d(TAG, "Augmenting tile for widget: " + widgetId); + Log.d(TAG, "Augmenting tile for existing widget: " + widgetId); PeopleSpaceTile tile = getTileForExistingWidget(widgetId); if (tile == null) { + if (DEBUG) { + Log.w(TAG, "Widget: " + widgetId + + ". Null tile for existing widget, skipping update."); + } return Optional.empty(); } String contactUriString = mSharedPrefs.getString(String.valueOf(widgetId), null); // Should never be null, but using ofNullable for extra safety. + PeopleTileKey key = new PeopleTileKey(tile); + if (DEBUG) Log.d(TAG, "Existing widget: " + widgetId + ". Tile key: " + key.toString()); return Optional.ofNullable( - augmentTileFromNotifications(tile, contactUriString, notifications)); + augmentTileFromNotifications(tile, key, contactUriString, notifications)); } /** Returns stored widgets for the conversation specified. */ @@ -644,12 +661,12 @@ public class PeopleSpaceWidgetManager { } synchronized (mLock) { - if (DEBUG) Log.d(TAG, "Add storage for : " + tile.getId()); + if (DEBUG) Log.d(TAG, "Add storage for : " + key.toString()); PeopleSpaceUtils.setSharedPreferencesStorageForTile(mContext, key, appWidgetId, tile.getContactUri()); } try { - if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + tile.getId()); + if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + key.toString()); mLauncherApps.cacheShortcuts(tile.getPackageName(), Collections.singletonList(tile.getId()), tile.getUserHandle(), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS); @@ -679,7 +696,7 @@ public class PeopleSpaceWidgetManager { if (DEBUG) Log.d(TAG, "Already registered listener"); return; } - if (DEBUG) Log.d(TAG, "Register listener for " + widgetId + " with " + key); + if (DEBUG) Log.d(TAG, "Register listener for " + widgetId + " with " + key.toString()); mListeners.put(key, newListener); } mPeopleManager.registerConversationListener(key.getPackageName(), @@ -750,7 +767,9 @@ public class PeopleSpaceWidgetManager { if (DEBUG) Log.d(TAG, "Cannot find listener to unregister"); return; } - if (DEBUG) Log.d(TAG, "Unregister listener for " + appWidgetId + " with " + key); + if (DEBUG) { + Log.d(TAG, "Unregister listener for " + appWidgetId + " with " + key.toString()); + } mListeners.remove(key); } mPeopleManager.unregisterConversationListener(registeredListener); diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt index feb27d804e5e..a626681c0b01 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt @@ -179,12 +179,16 @@ class PrivacyDialogController( } uiExecutor.execute { val elements = filterAndSelect(items) - val d = dialogProvider.makeDialog(context, elements, this::startActivity) - d.setShowForAllUsers(true) - d.addOnDismissListener(onDialogDismissed) - d.show() - privacyLogger.logShowDialogContents(elements) - dialog = d + if (elements.isNotEmpty()) { + val d = dialogProvider.makeDialog(context, elements, this::startActivity) + d.setShowForAllUsers(true) + d.addOnDismissListener(onDialogDismissed) + d.show() + privacyLogger.logShowDialogContents(elements) + dialog = d + } else { + Log.w(TAG, "Trying to show empty dialog") + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt index 63ec6e5db017..76199bfab0e0 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt @@ -58,7 +58,7 @@ data class PrivacyItem( val paused: Boolean = false ) { val log = "(${privacyType.logName}, ${application.packageName}(${application.uid}), " + - "$timeStampElapsed)" + "$timeStampElapsed, paused=$paused)" } data class PrivacyApplication(val packageName: String, val uid: Int) diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt index 8b27b6ecbfd1..e072b4a3646c 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt @@ -151,7 +151,9 @@ class PrivacyItemController @Inject constructor( return } val userId = UserHandle.getUserId(uid) - if (userId in currentUserIds) { + if (userId in currentUserIds || + code == AppOpsManager.OP_PHONE_CALL_MICROPHONE || + code == AppOpsManager.OP_PHONE_CALL_CAMERA) { logger.logUpdatedItemFromAppOps(code, uid, packageName, active) update(false) } diff --git a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt index acce945736f0..7c82a82179ee 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt @@ -116,6 +116,12 @@ class PrivacyLogger @Inject constructor( }) } + fun logEmptyDialog() { + log(LogLevel.WARNING, {}, { + "Trying to show an empty dialog" + }) + } + fun logPrivacyDialogDismissed() { log(LogLevel.INFO, {}, { "Privacy dialog dismissed" diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index f7fa5bfc4248..c552e89a3625 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -8,7 +8,6 @@ import android.animation.PropertyValuesHolder; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; -import android.graphics.Rect; import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; @@ -63,7 +62,6 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { private int mPageToRestore = -1; private int mLayoutOrientation; private int mLayoutDirection; - private final Rect mClippingRect; private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger(); private int mExcessHeight; private int mLastExcessHeight; @@ -78,14 +76,16 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { setCurrentItem(0, false); mLayoutOrientation = getResources().getConfiguration().orientation; mLayoutDirection = getLayoutDirection(); - mClippingRect = new Rect(); - - // Make sure there's a space between pages when scroling - setPageMargin(context.getResources().getDimensionPixelOffset( - R.dimen.qs_tile_margin_horizontal)); } private int mLastMaxHeight = -1; + @Override + public void setPageMargin(int marginPixels) { + if (marginPixels != getPageMargin()) { + super.setPageMargin(marginPixels); + } + } + public void saveInstanceState(Bundle outState) { outState.putInt(CURRENT_PAGE, getCurrentItem()); } @@ -353,14 +353,6 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { } @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - // Clip to margins - mClippingRect.set(0, 0, (r - l), b - t); - setClipBounds(mClippingRect); - } - - @Override public boolean setMinRows(int minRows) { mMinRows = minRows; boolean changed = false; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java index 294d76590fed..be96ba8a09d7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java @@ -35,6 +35,7 @@ import com.android.systemui.qs.tileimpl.HeightOverrideable; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; +import com.android.wm.shell.animation.Interpolators; import java.util.ArrayList; import java.util.Collection; @@ -80,7 +81,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha private QSExpansionPathInterpolator mQSExpansionPathInterpolator; private TouchAnimator mFirstPageAnimator; private TouchAnimator mFirstPageDelayedAnimator; - private TouchAnimator mTranslationXAnimator; private TouchAnimator mTranslationYAnimator; private TouchAnimator mNonfirstPageAnimator; private TouchAnimator mNonfirstPageDelayedAnimator; @@ -219,10 +219,29 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha mOnFirstPage = isFirst; } + private void translateContent( + View qqsView, + View qsView, + View commonParent, + int yOffset, + int[] temp, + TouchAnimator.Builder animatorBuilder + ) { + getRelativePosition(temp, qqsView, commonParent); + int qqsPos = temp[1]; + getRelativePosition(temp, qsView, commonParent); + int qsPos = temp[1]; + + int diff = qsPos - qqsPos - yOffset; + animatorBuilder.addFloat(qqsView, "translationY", 0, diff); + animatorBuilder.addFloat(qsView, "translationY", -diff, 0); + mAllViews.add(qqsView); + mAllViews.add(qsView); + } + private void updateAnimators() { mNeedsAnimatorUpdate = false; TouchAnimator.Builder firstPageBuilder = new Builder(); - TouchAnimator.Builder translationXBuilder = new Builder(); TouchAnimator.Builder translationYBuilder = new Builder(); Collection<QSTile> tiles = mHost.getTiles(); @@ -241,7 +260,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha QSTileLayout tileLayout = mQsPanelController.getTileLayout(); mAllViews.add((View) tileLayout); int height = mQs.getView() != null ? mQs.getView().getMeasuredHeight() : 0; - int width = mQs.getView() != null ? mQs.getView().getMeasuredWidth() : 0; int heightDiff = height - mQs.getHeader().getBottom() + mQs.getHeader().getPaddingBottom(); if (!mTranslateWhileExpanding) { @@ -268,68 +286,62 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha QSTileView quickTileView = mQuickQSPanelController.getTileView(tile); if (quickTileView == null) continue; - getRelativePosition(loc1, quickTileView.getIcon().getIconView(), view); - getRelativePosition(loc2, tileIcon, view); - final int xDiff = loc2[0] - loc1[0]; - int yDiff = loc2[1] - loc1[1]; - - if (count < tileLayout.getNumVisibleTiles()) { - getRelativePosition(loc1, quickTileView, view); - getRelativePosition(loc2, tileView, view); - int yOffset = loc2[1] - loc1[1]; - // Move the quick tile right from its location to the new one. - View v = quickTileView.getIcon(); - translationXBuilder.addFloat(v, "translationX", 0, xDiff); - translationYBuilder.addFloat(v, "translationY", 0, yDiff - yOffset); - mAllViews.add(v); - - // Move the real tile from the quick tile position to its final - // location. - v = tileIcon; - translationXBuilder.addFloat(v, "translationX", -xDiff, 0); - translationYBuilder.addFloat(v, "translationY", -yDiff + yOffset, 0); - - // Offset the translation animation on the views - // (that goes from 0 to getOffsetTranslation) - int offsetWithQSBHTranslation = - yOffset - mQuickStatusBarHeader.getOffsetTranslation(); - translationYBuilder.addFloat(quickTileView, "translationY", 0, - offsetWithQSBHTranslation); - translationYBuilder.addFloat(tileView, "translationY", - -offsetWithQSBHTranslation, 0); - - if (mQQSTileHeightAnimator == null) { - mQQSTileHeightAnimator = new HeightExpansionAnimator(this, - quickTileView.getHeight(), tileView.getHeight()); - qqsTileHeight = quickTileView.getHeight(); - } - - mQQSTileHeightAnimator.addView(quickTileView); - View qqsLabelContainer = quickTileView.getLabelContainer(); - View qsLabelContainer = tileView.getLabelContainer(); - - getRelativePosition(loc1, qqsLabelContainer, view); - getRelativePosition(loc2, qsLabelContainer, view); - yDiff = loc2[1] - loc1[1] - yOffset; - - translationYBuilder.addFloat(qqsLabelContainer, "translationY", 0, yDiff); - translationYBuilder.addFloat(qsLabelContainer, "translationY", -yDiff, 0); - mAllViews.add(qqsLabelContainer); - mAllViews.add(qsLabelContainer); - } else { // These tiles disappear when expanding - firstPageBuilder.addFloat(quickTileView, "alpha", 1, 0); - translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff); - - // xDiff is negative here and this makes it "more" negative - final int translationX = - mQsPanelController.isLayoutRtl() ? xDiff - width : xDiff + width; - translationXBuilder.addFloat(quickTileView, "translationX", 0, - translationX); + getRelativePosition(loc1, quickTileView, view); + getRelativePosition(loc2, tileView, view); + int yOffset = loc2[1] - loc1[1]; + + // Offset the translation animation on the views + // (that goes from 0 to getOffsetTranslation) + int offsetWithQSBHTranslation = + yOffset - mQuickStatusBarHeader.getOffsetTranslation(); + translationYBuilder.addFloat(quickTileView, "translationY", 0, + offsetWithQSBHTranslation); + translationYBuilder.addFloat(tileView, "translationY", + -offsetWithQSBHTranslation, 0); + + if (mQQSTileHeightAnimator == null) { + mQQSTileHeightAnimator = new HeightExpansionAnimator(this, + quickTileView.getHeight(), tileView.getHeight()); + qqsTileHeight = quickTileView.getHeight(); } + mQQSTileHeightAnimator.addView(quickTileView); + + // Icons + translateContent( + quickTileView.getIcon(), + tileView.getIcon(), + view, + yOffset, + loc1, + translationYBuilder + ); + + // Label containers + translateContent( + quickTileView.getLabelContainer(), + tileView.getLabelContainer(), + view, + yOffset, + loc1, + translationYBuilder + ); + + // Secondary icon + translateContent( + quickTileView.getSecondaryIcon(), + tileView.getSecondaryIcon(), + view, + yOffset, + loc1, + translationYBuilder + ); + + firstPageBuilder.addFloat(quickTileView.getSecondaryLabel(), "alpha", 0, 1); + mQuickQsViews.add(tileView); - mAllViews.add(tileView.getIcon()); mAllViews.add(quickTileView); + mAllViews.add(quickTileView.getSecondaryLabel()); } else if (mFullRows && isIconInAnimatedRow(count)) { firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0); @@ -363,11 +375,14 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha // Make brightness appear static position and alpha in through second half. View brightness = mQsPanelController.getBrightnessView(); if (brightness != null) { - firstPageBuilder.addFloat(brightness, "translationY", heightDiff, 0); + firstPageBuilder.addFloat(brightness, "translationY", + brightness.getMeasuredHeight() * 0.5f, 0); mBrightnessAnimator = new TouchAnimator.Builder() .addFloat(brightness, "alpha", 0, 1) - .setStartDelay(.5f) + .addFloat(brightness, "scaleY", 0.3f, 1) + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .build(); + brightness.setPivotY(0); mAllViews.add(brightness); } else { mBrightnessAnimator = null; @@ -391,17 +406,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha if (mQsPanelController.getDivider() != null) { mAllViews.add(mQsPanelController.getDivider()); } - - float px = 0; - if (tiles.size() <= 3) { - px = 1; - } else if (tiles.size() <= 6) { - px = .4f; - } - mQSExpansionPathInterpolator.setControlX2(px); - translationXBuilder.setInterpolator(mQSExpansionPathInterpolator.getXInterpolator()); translationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator()); - mTranslationXAnimator = translationXBuilder.build(); mTranslationYAnimator = translationYBuilder.build(); if (mQQSTileHeightAnimator != null) { mQQSTileHeightAnimator.setInterpolator( @@ -474,11 +479,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha mQuickQsPanel.setAlpha(1); mFirstPageAnimator.setPosition(position); mFirstPageDelayedAnimator.setPosition(position); - mTranslationXAnimator.setPosition(position); mTranslationYAnimator.setPosition(position); - if (mBrightnessAnimator != null) { - mBrightnessAnimator.setPosition(position); - } if (mQQSTileHeightAnimator != null) { mQQSTileHeightAnimator.setPosition(position); } @@ -491,6 +492,9 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha } if (mAllowFancy) { mAllPagesDelayedAnimator.setPosition(position); + if (mBrightnessAnimator != null) { + mBrightnessAnimator.setPosition(position); + } } } @@ -527,6 +531,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha v.setAlpha(1); v.setTranslationX(0); v.setTranslationY(0); + v.setScaleY(1f); if (v instanceof SideLabelTileLayout) { ((SideLabelTileLayout) v).setClipChildren(false); ((SideLabelTileLayout) v).setClipToPadding(false); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index e89803d16779..f486c535d9e2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -60,7 +60,7 @@ public class QSContainerImpl extends FrameLayout { private int mFancyClippingBottom; private final float[] mFancyClippingRadii = new float[] {0, 0, 0, 0, 0, 0, 0, 0}; private final Path mFancyClippingPath = new Path(); - private int mBackgroundBottom = -1; + private int mBackgroundBottom = 0; private int mHeightOverride = -1; private View mQSDetail; private QuickStatusBarHeader mHeader; @@ -68,11 +68,8 @@ public class QSContainerImpl extends FrameLayout { private QSCustomizer mQSCustomizer; private NonInterceptingScrollView mQSPanelContainer; - private View mBackground; - private int mSideMargins; private boolean mQsDisabled; - private boolean mBackgroundVisible; private int mContentPadding = -1; private boolean mAnimateBottomOnNextLayout; private int mNavBarInset = 0; @@ -89,7 +86,6 @@ public class QSContainerImpl extends FrameLayout { mQSDetail = findViewById(R.id.qs_detail); mHeader = findViewById(R.id.header); mQSCustomizer = findViewById(R.id.qs_customize); - mBackground = findViewById(R.id.quick_settings_background); mHeader.getHeaderQsPanel().setMediaVisibilityChangedListener((visible) -> { if (mHeader.getHeaderQsPanel().isShown()) { mAnimateBottomOnNextLayout = true; @@ -111,13 +107,9 @@ public class QSContainerImpl extends FrameLayout { // We're saving the bottom separately since otherwise the bottom would be overridden in // the layout and the animation wouldn't properly start at the old position. mBackgroundBottom = value; - mBackground.setBottom(value); } private float getBackgroundBottom() { - if (mBackgroundBottom == -1) { - return mBackground.getBottom(); - } return mBackgroundBottom; } @@ -134,14 +126,6 @@ public class QSContainerImpl extends FrameLayout { return true; } - /** - * If QS should have a solid or transparent background. - */ - public void setBackgroundVisible(boolean visible) { - mBackgroundVisible = visible; - updateBackgroundVisibility(); - } - @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { mNavBarInset = insets.getInsets(WindowInsets.Type.navigationBars()).bottom; @@ -154,11 +138,9 @@ public class QSContainerImpl extends FrameLayout { // bottom and footer are inside the screen. MarginLayoutParams layoutParams = (MarginLayoutParams) mQSPanelContainer.getLayoutParams(); - // The footer is pinned to the bottom of QSPanel (same bottoms), therefore we don't need to - // subtract its height. We do not care if the collapsed notifications fit in the screen. - int maxQs = getDisplayHeight() - layoutParams.topMargin - layoutParams.bottomMargin + int availableScreenHeight = getDisplayHeight() - mNavBarInset; + int maxQs = availableScreenHeight - layoutParams.topMargin - layoutParams.bottomMargin - getPaddingBottom(); - maxQs -= mNavBarInset; int padding = mPaddingLeft + mPaddingRight + layoutParams.leftMargin + layoutParams.rightMargin; final int qsPanelWidthSpec = getChildMeasureSpec(widthMeasureSpec, padding, @@ -169,7 +151,7 @@ public class QSContainerImpl extends FrameLayout { int height = layoutParams.topMargin + layoutParams.bottomMargin + mQSPanelContainer.getMeasuredHeight() + getPaddingBottom(); super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); + MeasureSpec.makeMeasureSpec(availableScreenHeight, MeasureSpec.EXACTLY)); // QSCustomizer will always be the height of the screen, but do this after // other measuring to avoid changing the height of the QS. mQSCustomizer.measure(widthMeasureSpec, @@ -210,11 +192,6 @@ public class QSContainerImpl extends FrameLayout { final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0; if (disabled == mQsDisabled) return; mQsDisabled = disabled; - updateBackgroundVisibility(); - } - - private void updateBackgroundVisibility() { - mBackground.setVisibility(mQsDisabled || !mBackgroundVisible ? GONE : VISIBLE); } void updateResources(QSPanelController qsPanelController, @@ -262,7 +239,6 @@ public class QSContainerImpl extends FrameLayout { mQSDetail.setBottom(getTop() + scrollBottom); int qsDetailBottomMargin = ((MarginLayoutParams) mQSDetail.getLayoutParams()).bottomMargin; mQSDetail.setBottom(getTop() + scrollBottom - qsDetailBottomMargin); - mBackground.setTop(mQSPanelContainer.getTop()); updateBackgroundBottom(scrollBottom, animate); } @@ -316,6 +292,9 @@ public class QSContainerImpl extends FrameLayout { if (view == mQSPanelContainer) { // QS panel lays out some of its content full width qsPanelController.setContentMargins(mContentPadding, mContentPadding); + // Set it as double the side margin (to simulate end margin of current page + + // start margin of next page). + qsPanelController.setPageMargin(2 * mSideMargins); } else if (view == mHeader) { // The header contains the QQS panel which needs to have special padding, to // visually align them. diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java index c4986cc4ac89..40967ede057e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java @@ -195,10 +195,10 @@ public class QSFooterView extends FrameLayout { mExpandClickListener = onClickListener; } - void setExpanded(boolean expanded, boolean isTunerEnabled) { + void setExpanded(boolean expanded, boolean isTunerEnabled, boolean multiUserEnabled) { if (mExpanded == expanded) return; mExpanded = expanded; - updateEverything(isTunerEnabled); + updateEverything(isTunerEnabled, multiUserEnabled); } /** */ @@ -251,16 +251,16 @@ public class QSFooterView extends FrameLayout { info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND); } - void disable(int state2, boolean isTunerEnabled) { + void disable(int state2, boolean isTunerEnabled, boolean multiUserEnabled) { final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0; if (disabled == mQsDisabled) return; mQsDisabled = disabled; - updateEverything(isTunerEnabled); + updateEverything(isTunerEnabled, multiUserEnabled); } - void updateEverything(boolean isTunerEnabled) { + void updateEverything(boolean isTunerEnabled, boolean multiUserEnabled) { post(() -> { - updateVisibilities(isTunerEnabled); + updateVisibilities(isTunerEnabled, multiUserEnabled); updateClickabilities(); setClickable(false); }); @@ -273,18 +273,19 @@ public class QSFooterView extends FrameLayout { mBuildText.setLongClickable(mBuildText.getVisibility() == View.VISIBLE); } - private void updateVisibilities(boolean isTunerEnabled) { + private void updateVisibilities(boolean isTunerEnabled, boolean multiUserEnabled) { mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE); mTunerIcon.setVisibility(isTunerEnabled ? View.VISIBLE : View.INVISIBLE); final boolean isDemo = UserManager.isDeviceInDemoMode(mContext); - mMultiUserSwitch.setVisibility(showUserSwitcher() ? View.VISIBLE : View.GONE); + mMultiUserSwitch.setVisibility( + showUserSwitcher(multiUserEnabled) ? View.VISIBLE : View.GONE); mSettingsButton.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE); mBuildText.setVisibility(mExpanded && mShouldShowBuildText ? View.VISIBLE : View.INVISIBLE); } - private boolean showUserSwitcher() { - return mExpanded && mMultiUserSwitch.isMultiUserEnabled(); + private boolean showUserSwitcher(boolean multiUserEnabled) { + return mExpanded && multiUserEnabled; } void onUserInfoChanged(Drawable picture, boolean isGuestUser) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java index 74ae3a698998..1fa926009861 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java @@ -38,7 +38,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.settings.UserTracker; -import com.android.systemui.statusbar.phone.MultiUserSwitch; +import com.android.systemui.statusbar.phone.MultiUserSwitchController; import com.android.systemui.statusbar.phone.SettingsButton; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.UserInfoController; @@ -60,16 +60,15 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme private final DeviceProvisionedController mDeviceProvisionedController; private final UserTracker mUserTracker; private final QSPanelController mQsPanelController; - private final QSDetailDisplayer mQsDetailDisplayer; private final QuickQSPanelController mQuickQSPanelController; private final TunerService mTunerService; private final MetricsLogger mMetricsLogger; private final FalsingManager mFalsingManager; + private final MultiUserSwitchController mMultiUserSwitchController; private final SettingsButton mSettingsButton; private final View mSettingsButtonContainer; private final TextView mBuildText; private final View mEdit; - private final MultiUserSwitch mMultiUserSwitch; private final PageIndicator mPageIndicator; private final View mPowerMenuLite; private final boolean mShowPMLiteButton; @@ -135,7 +134,8 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme QSFooterViewController(QSFooterView view, UserManager userManager, UserInfoController userInfoController, ActivityStarter activityStarter, DeviceProvisionedController deviceProvisionedController, UserTracker userTracker, - QSPanelController qsPanelController, QSDetailDisplayer qsDetailDisplayer, + QSPanelController qsPanelController, + MultiUserSwitchController multiUserSwitchController, QuickQSPanelController quickQSPanelController, TunerService tunerService, MetricsLogger metricsLogger, FalsingManager falsingManager, @Named(PM_LITE_ENABLED) boolean showPMLiteButton, @@ -147,17 +147,16 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme mDeviceProvisionedController = deviceProvisionedController; mUserTracker = userTracker; mQsPanelController = qsPanelController; - mQsDetailDisplayer = qsDetailDisplayer; mQuickQSPanelController = quickQSPanelController; mTunerService = tunerService; mMetricsLogger = metricsLogger; mFalsingManager = falsingManager; + mMultiUserSwitchController = multiUserSwitchController; mSettingsButton = mView.findViewById(R.id.settings_button); mSettingsButtonContainer = mView.findViewById(R.id.settings_button_container); mBuildText = mView.findViewById(R.id.build); 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; @@ -165,6 +164,12 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme } @Override + protected void onInit() { + super.onInit(); + mMultiUserSwitchController.init(); + } + + @Override protected void onViewAttached() { if (mShowPMLiteButton) { mPowerMenuLite.setVisibility(View.VISIBLE); @@ -199,9 +204,8 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme mQsPanelController.showEdit(view)); }); - mMultiUserSwitch.setQSDetailDisplayer(mQsDetailDisplayer); mQsPanelController.setFooterPageIndicator(mPageIndicator); - mView.updateEverything(isTunerEnabled()); + mView.updateEverything(isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled()); } @Override @@ -217,10 +221,10 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme @Override public void setExpanded(boolean expanded) { mExpanded = expanded; - mView.setExpanded(expanded, isTunerEnabled()); + mView.setExpanded( + expanded, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled()); } - @Override public int getHeight() { return mView.getHeight(); @@ -258,7 +262,7 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme @Override public void disable(int state1, int state2, boolean animate) { - mView.disable(state2, isTunerEnabled()); + mView.disable(state2, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled()); } private void startSettingsActivity() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index d5cb777416a7..53b4d5f7d5f8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -172,7 +172,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mQSContainerImplController = qsFragmentComponent.getQSContainerImplController(); mQSContainerImplController.init(); mContainer = mQSContainerImplController.getView(); - mContainer.setBackgroundVisible(!mFeatureFlags.isShadeOpaque()); mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter); mQSAnimator = qsFragmentComponent.getQSAnimator(); @@ -480,8 +479,12 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca private void updateQsBounds() { if (mLastQSExpansion == 1.0f) { // Fully expanded, let's set the layout bounds as clip bounds. This is necessary because - // it's a scrollview and otherwise wouldn't be clipped. - mQsBounds.set(0, 0, mQSPanelScrollView.getWidth(), mQSPanelScrollView.getHeight()); + // it's a scrollview and otherwise wouldn't be clipped. However, we set the horizontal + // bounds so the pages go to the ends of QSContainerImpl + ViewGroup.MarginLayoutParams lp = + (ViewGroup.MarginLayoutParams) mQSPanelScrollView.getLayoutParams(); + mQsBounds.set(-lp.leftMargin, 0, mQSPanelScrollView.getWidth() + lp.rightMargin, + mQSPanelScrollView.getHeight()); } mQSPanelScrollView.setClipBounds(mQsBounds); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index f89e70a08cc7..4e16b7414ff1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -138,7 +138,7 @@ public class QSPanel extends LinearLayout implements Tunable { mHorizontalTileLayout = createHorizontalTileLayout(); LayoutParams lp = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1); - int marginSize = (int) mContext.getResources().getDimension(R.dimen.qqs_media_spacing); + int marginSize = (int) mContext.getResources().getDimension(R.dimen.qs_media_padding); lp.setMarginStart(0); lp.setMarginEnd(marginSize); lp.gravity = Gravity.CENTER_VERTICAL; @@ -301,12 +301,6 @@ public class QSPanel extends LinearLayout implements Tunable { protected void updatePadding() { final Resources res = mContext.getResources(); int padding = res.getDimensionPixelSize(R.dimen.qs_panel_padding_top); - if (mUsingHorizontalLayout) { - // When using the horizontal layout, our space is quite constrained. We therefore - // reduce some of the padding on the top, which makes the brightness bar overlapp, - // but since that has naturally quite a bit of built in padding, that's fine. - padding = (int) (padding * 0.6f); - } setPaddingRelative(getPaddingStart(), padding, getPaddingEnd(), @@ -326,6 +320,7 @@ public class QSPanel extends LinearLayout implements Tunable { super.onConfigurationChanged(newConfig); mOnConfigurationChangedListeners.forEach( listener -> listener.onConfigurationChange(newConfig)); + switchSecurityFooter(); } @Override @@ -364,20 +359,26 @@ public class QSPanel extends LinearLayout implements Tunable { switchToParent((View) newLayout, parent, index); index++; + if (mFooter != null) { + // Then the footer with the settings + switchToParent(mFooter, parent, index); + index++; + } + + // The security footer is switched on orientation changes + } + + private void switchSecurityFooter() { if (mSecurityFooter != null) { - if (mUsingHorizontalLayout && mHeaderContainer != null) { + if (mContext.getResources().getConfiguration().orientation + == Configuration.ORIENTATION_LANDSCAPE && mHeaderContainer != null + && !mSecurityFooter.getParent().equals(mHeaderContainer)) { // Adding the security view to the header, that enables us to avoid scrolling switchToParent(mSecurityFooter, mHeaderContainer, 0); } else { - switchToParent(mSecurityFooter, parent, index); - index++; + switchToParent(mSecurityFooter, this, -1); } } - - if (mFooter != null) { - // Then the footer with the settings - switchToParent(mFooter, parent, index); - } } private void switchToParent(View child, ViewGroup parent, int index) { @@ -668,6 +669,17 @@ public class QSPanel extends LinearLayout implements Tunable { public void setSecurityFooter(View view) { mSecurityFooter = view; + switchSecurityFooter(); + } + + protected void setPageMargin(int pageMargin) { + if (mRegularTileLayout instanceof PagedTileLayout) { + ((PagedTileLayout) mRegularTileLayout).setPageMargin(pageMargin); + } + if (mHorizontalTileLayout != mRegularTileLayout + && mHorizontalTileLayout instanceof PagedTileLayout) { + ((PagedTileLayout) mHorizontalTileLayout).setPageMargin(pageMargin); + } } void setUsingHorizontalLayout(boolean horizontal, ViewGroup mediaHostView, boolean force, diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java index 93ccfc7288e7..fff3d1fe4b5f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java @@ -321,5 +321,9 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> { public boolean isExpanded() { return mView.isExpanded(); } + + void setPageMargin(int pageMargin) { + mView.setPageMargin(pageMargin); + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java index 670475fac5ef..baf781d38441 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java @@ -16,6 +16,8 @@ package com.android.systemui.qs; import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.systemui.qs.dagger.QSFragmentModule.QS_SECURITY_FOOTER_VIEW; @@ -26,6 +28,8 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.UserInfo; +import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; @@ -68,7 +72,6 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen private final View mRootView; private final TextView mFooterText; - private final ImageView mFooterIcon; private final ImageView mPrimaryFooterIcon; private final Context mContext; private final Callback mCallback = new Callback(); @@ -83,7 +86,6 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen private boolean mIsVisible; private CharSequence mFooterTextContent = null; - private int mFooterTextId; private int mFooterIconId; private Drawable mPrimaryFooterIconDrawable; @@ -94,7 +96,6 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen mRootView = rootView; mRootView.setOnClickListener(this); mFooterText = mRootView.findViewById(R.id.footer_text); - mFooterIcon = mRootView.findViewById(R.id.footer_icon); mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon); mFooterIconId = R.drawable.ic_info_outline; mContext = rootView.getContext(); @@ -120,6 +121,23 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen public void onConfigurationChanged() { FontSizeUtils.updateFontSize(mFooterText, R.dimen.qs_tile_text_size); + + Resources r = mContext.getResources(); + + mFooterText.setMaxLines(r.getInteger(R.integer.qs_security_footer_maxLines)); + int padding = r.getDimensionPixelSize(R.dimen.qs_footer_padding); + mRootView.setPaddingRelative(padding, padding, padding, padding); + + int verticalMargin = r.getDimensionPixelSize(R.dimen.qs_security_footer_vertical_margin); + ViewGroup.MarginLayoutParams lp = + (ViewGroup.MarginLayoutParams) mRootView.getLayoutParams(); + lp.topMargin = verticalMargin; + lp.bottomMargin = verticalMargin; + lp.width = r.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT + ? MATCH_PARENT : WRAP_CONTENT; + mRootView.setLayoutParams(lp); + + mRootView.setBackground(mContext.getDrawable(R.drawable.qs_security_footer_background)); } public View getView() { @@ -189,7 +207,6 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen } if (mFooterIconId != footerIconId) { mFooterIconId = footerIconId; - mMainHandler.post(mUpdateIcon); } // Update the primary icon @@ -315,7 +332,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen mDialog.setView(createDialogView()); mDialog.show(); - mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, + mDialog.getWindow().setLayout(MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } @@ -575,19 +592,14 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen == DEVICE_OWNER_TYPE_FINANCED; } - private final Runnable mUpdateIcon = new Runnable() { - @Override - public void run() { - mFooterIcon.setImageResource(mFooterIconId); - } - }; - private final Runnable mUpdatePrimaryIcon = new Runnable() { @Override public void run() { - mPrimaryFooterIcon.setVisibility(mPrimaryFooterIconDrawable != null - ? View.VISIBLE : View.GONE); - mPrimaryFooterIcon.setImageDrawable(mPrimaryFooterIconDrawable); + if (mPrimaryFooterIconDrawable != null) { + mPrimaryFooterIcon.setImageDrawable(mPrimaryFooterIconDrawable); + } else { + mPrimaryFooterIcon.setImageResource(mFooterIconId); + } } }; diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java index f673364c7e17..ca8f68160454 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java @@ -53,6 +53,7 @@ public class TouchAnimator { } public void setPosition(float fraction) { + if (Float.isNaN(fraction)) return; float t = MathUtils.constrain((fraction - mStartDelay) / mSpan, 0, 1); if (mInterpolator != null) { t = mInterpolator.getInterpolation(t); diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java index 3a5adce51d0d..34aac492dc30 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java @@ -34,6 +34,7 @@ import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QuickQSPanel; import com.android.systemui.qs.QuickStatusBarHeader; import com.android.systemui.qs.customize.QSCustomizer; +import com.android.systemui.statusbar.phone.MultiUserSwitch; import javax.inject.Named; @@ -74,6 +75,12 @@ public interface QSFragmentModule { /** */ @Provides + static MultiUserSwitch providesMultiUserSWitch(QSFooterView qsFooterView) { + return qsFooterView.findViewById(R.id.multi_user_switch); + } + + /** */ + @Provides static QSPanel provideQSPanel(@RootView View view) { return view.findViewById(R.id.quick_settings_panel); } @@ -129,7 +136,7 @@ public interface QSFragmentModule { @QSThemedContext LayoutInflater layoutInflater, QSPanel qsPanel ) { - return layoutInflater.inflate(R.layout.quick_settings_footer, qsPanel, false); + return layoutInflater.inflate(R.layout.quick_settings_security_footer, qsPanel, false); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/ButtonRelativeLayout.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/ButtonRelativeLayout.java index 2c17b874dcab..962537a01fe2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/ButtonRelativeLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/ButtonRelativeLayout.java @@ -16,11 +16,17 @@ package com.android.systemui.qs.tileimpl; import android.content.Context; import android.util.AttributeSet; +import android.view.View; import android.widget.Button; import android.widget.RelativeLayout; +/** + * Used for QS tile labels + */ public class ButtonRelativeLayout extends RelativeLayout { + private View mIgnoredView; + public ButtonRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); } @@ -29,4 +35,27 @@ public class ButtonRelativeLayout extends RelativeLayout { public CharSequence getAccessibilityClassName() { return Button.class.getName(); } + + /** + * Set a view to be ignored for measure. + * + * The view will be measured and laid out, but its size will be subtracted from the total size + * of this view. It assumes that this view only contributes vertical height. + */ + public void setIgnoredView(View view) { + if (mIgnoredView == null || mIgnoredView.getParent() == this) { + mIgnoredView = view; + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (mIgnoredView != null && mIgnoredView.getVisibility() != GONE) { + int height = mIgnoredView.getMeasuredHeight(); + MarginLayoutParams lp = (MarginLayoutParams) mIgnoredView.getLayoutParams(); + height = height - lp.bottomMargin - lp.topMargin; + setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() - height); + } + } } 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 3d5a709a5fdd..50417e9ab259 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java @@ -22,7 +22,6 @@ import android.text.TextUtils; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; @@ -44,7 +43,7 @@ public class QSTileView extends QSTileBaseView { protected TextView mSecondLine; private ImageView mPadLock; protected int mState; - protected ViewGroup mLabelContainer; + protected ButtonRelativeLayout mLabelContainer; private View mExpandIndicator; private View mExpandSpace; protected ColorStateList mColorLabelActive; @@ -92,7 +91,7 @@ public class QSTileView extends QSTileBaseView { } protected void createLabel() { - mLabelContainer = (ViewGroup) LayoutInflater.from(getContext()) + mLabelContainer = (ButtonRelativeLayout) LayoutInflater.from(getContext()) .inflate(R.layout.qs_tile_label, this, false); mLabelContainer.setClipChildren(false); mLabelContainer.setClipToPadding(false); @@ -140,7 +139,7 @@ public class QSTileView extends QSTileBaseView { } if (!Objects.equals(mSecondLine.getText(), state.secondaryLabel)) { mSecondLine.setText(state.secondaryLabel); - mSecondLine.setVisibility(TextUtils.isEmpty(state.secondaryLabel) || mCollapsedView + mSecondLine.setVisibility(TextUtils.isEmpty(state.secondaryLabel) ? View.GONE : View.VISIBLE); } boolean dualTarget = mDualTargetAllowed && state.dualTarget; @@ -193,4 +192,9 @@ public class QSTileView extends QSTileBaseView { public View getLabelContainer() { return mLabelContainer; } + + @Override + public View getSecondaryLabel() { + return mSecondLine; + } } 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 b9533237e3d5..70d51ee1c516 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt @@ -25,6 +25,7 @@ import android.graphics.drawable.RippleDrawable import android.service.quicksettings.Tile.STATE_ACTIVE import android.view.Gravity import android.view.View +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.widget.ImageView import android.widget.LinearLayout import android.widget.RelativeLayout @@ -43,7 +44,7 @@ open class QSTileViewHorizontal( private var paintColor = Color.WHITE private var paintAnimator: ValueAnimator? = null private var labelAnimator: ValueAnimator? = null - private var mSideView: ImageView = ImageView(mContext) + private var sideView: ImageView = ImageView(mContext) override var heightOverride: Int = HeightOverrideable.NO_OVERRIDE init { @@ -59,13 +60,14 @@ open class QSTileViewHorizontal( val iconSize = context.resources.getDimensionPixelSize(R.dimen.qs_icon_size) addView(mIcon, 0, LayoutParams(iconSize, iconSize)) - mSideView.visibility = View.GONE - addView( - mSideView, - -1, - LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply { - gravity = Gravity.CENTER_VERTICAL - }) + sideView.visibility = View.GONE + val sideViewLayoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { + gravity = Gravity.CENTER_VERTICAL + marginStart = context.resources.getDimensionPixelSize(R.dimen.qs_label_container_margin) + } + addView(sideView, -1, sideViewLayoutParams) + sideView.adjustViewBounds = true + sideView.scaleType = ImageView.ScaleType.FIT_CENTER mColorLabelActive = ColorStateList.valueOf(getColorForState(getContext(), STATE_ACTIVE)) changeLabelColor(getLabelColor(mState)) // Matches the default state of the tile @@ -89,16 +91,17 @@ open class QSTileViewHorizontal( mLabelContainer.setPadding(0, 0, 0, 0) (mLabelContainer.layoutParams as MarginLayoutParams).apply { marginStart = context.resources.getDimensionPixelSize(R.dimen.qs_label_container_margin) + marginEnd = 0 + gravity = Gravity.CENTER_VERTICAL or Gravity.START } mLabel.gravity = Gravity.START mLabel.textDirection = TEXT_DIRECTION_LOCALE mSecondLine.gravity = Gravity.START mSecondLine.textDirection = TEXT_DIRECTION_LOCALE - (mLabelContainer.layoutParams as LayoutParams).gravity = - Gravity.CENTER_VERTICAL or Gravity.START if (mCollapsedView) { - mSecondLine.visibility = GONE + mSecondLine.alpha = 0f + mLabelContainer.setIgnoredView(mSecondLine) } } @@ -183,9 +186,7 @@ open class QSTileViewHorizontal( private fun setLabelsColor(color: ColorStateList) { mLabel.setTextColor(color) - if (!mCollapsedView) { - mSecondLine.setTextColor(color) - } + mSecondLine.setTextColor(color) } private fun clearBackgroundAnimator() { @@ -198,19 +199,17 @@ open class QSTileViewHorizontal( private fun loadSideViewDrawableIfNecessary(state: QSTile.State) { if (state.sideViewDrawable != null) { - (mSideView.layoutParams as MarginLayoutParams).apply { - marginStart = - context.resources.getDimensionPixelSize(R.dimen.qs_label_container_margin) - } - mSideView.setImageDrawable(state.sideViewDrawable) - mSideView.visibility = View.VISIBLE - mSideView.adjustViewBounds = true - mSideView.scaleType = ImageView.ScaleType.FIT_CENTER + sideView.setImageDrawable(state.sideViewDrawable) + sideView.visibility = View.VISIBLE } else { - mSideView.setImageDrawable(null) - mSideView.visibility = GONE + sideView.setImageDrawable(null) + sideView.visibility = GONE } } override fun handleExpand(dualTarget: Boolean) {} + + override fun getSecondaryIcon(): View { + return sideView + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java index ff830bc952c1..be40423df3fa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java @@ -129,8 +129,15 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> { Intent intent = new Intent(mContext, WalletActivity.class) .setAction(Intent.ACTION_VIEW) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); - mActivityStarter.startActivity(intent, true /* dismissShade */, - animationController); + if (mKeyguardStateController.isUnlocked()) { + mActivityStarter.startActivity(intent, true /* dismissShade */, + animationController); + } else { + mHost.collapsePanels(); + // Do not use ActivityStarter here because the WalletActivity is required to be + // started without prompting keyguard when the device is locked. + mContext.startActivity(intent); + } } else { if (mQuickAccessWalletClient.createWalletIntent() == null) { Log.w(TAG, "Could not get intent of the wallet app."); @@ -147,7 +154,7 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> { protected void handleUpdateState(State state, Object arg) { state.label = mLabel; state.contentDescription = state.label; - state.icon = ResourceIcon.get(R.drawable.ic_qs_wallet); + state.icon = ResourceIcon.get(R.drawable.ic_wallet_lockscreen); boolean isDeviceLocked = !mKeyguardStateController.isUnlocked(); if (mQuickAccessWalletClient.isWalletServiceAvailable()) { if (mHasCard) { @@ -219,7 +226,12 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> { refreshState(); return; } - mCardViewDrawable = cards.get(0).getCardImage().loadDrawable(mContext); + int selectedIndex = response.getSelectedIndex(); + if (selectedIndex >= cards.size()) { + Log.d(TAG, "Selected card index out of bounds."); + return; + } + mCardViewDrawable = cards.get(selectedIndex).getCardImage().loadDrawable(mContext); mHasCard = true; refreshState(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java index 8ddd4c9816cd..2458223310cf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java @@ -34,10 +34,13 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.drawable.CircleFramedDrawable; import com.android.systemui.R; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.qs.PseudoGridView; import com.android.systemui.qs.QSUserSwitcherEvent; import com.android.systemui.statusbar.policy.UserSwitcherController; +import javax.inject.Inject; + /** * Quick settings detail view for user switching. */ @@ -54,9 +57,9 @@ public class UserDetailView extends PseudoGridView { R.layout.qs_user_detail, parent, attach); } - public void createAndSetAdapter(UserSwitcherController controller, - UiEventLogger uiEventLogger) { - mAdapter = new Adapter(mContext, controller, uiEventLogger); + /** Set a {@link android.widget.BaseAdapter} */ + public void setAdapter(Adapter adapter) { + mAdapter = adapter; ViewGroupAdapterBridge.link(this, mAdapter); } @@ -71,13 +74,16 @@ public class UserDetailView extends PseudoGridView { protected UserSwitcherController mController; private View mCurrentUserView; private final UiEventLogger mUiEventLogger; + private final FalsingManager mFalsingManager; + @Inject public Adapter(Context context, UserSwitcherController controller, - UiEventLogger uiEventLogger) { + UiEventLogger uiEventLogger, FalsingManager falsingManager) { super(controller); mContext = context; mController = controller; mUiEventLogger = uiEventLogger; + mFalsingManager = falsingManager; } @Override @@ -140,6 +146,10 @@ public class UserDetailView extends PseudoGridView { @Override public void onClick(View view) { + if (mFalsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY)) { + return; + } + UserSwitcherController.UserRecord tag = (UserSwitcherController.UserRecord) view.getTag(); if (tag.isDisabledByAdmin) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 850f8a5959a0..f078ccd9d382 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -408,6 +408,7 @@ public class OverviewProxyService extends CurrentUserTracker implements mPipOptional.ifPresent( pip -> pip.setPinnedStackAnimationType( PipAnimationController.ANIM_TYPE_ALPHA)); + mHandler.post(() -> notifySwipeToHomeFinishedInternal()); } finally { Binder.restoreCallingIdentity(token); } @@ -886,6 +887,12 @@ public class OverviewProxyService extends CurrentUserTracker implements } } + public void notifySwipeToHomeFinishedInternal() { + for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { + mConnectionCallbacks.get(i).onSwipeToHomeFinished(); + } + } + public void notifyAssistantVisibilityChanged(float visibility) { try { if (mOverviewProxy != null) { @@ -962,6 +969,7 @@ public class OverviewProxyService extends CurrentUserTracker implements public interface OverviewProxyListener { default void onConnectionChanged(boolean isConnected) {} default void onQuickStepStarted() {} + default void onSwipeToHomeFinished() {} default void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {} default void onOverviewShown(boolean fromHome) {} default void onQuickScrubStarted() {} diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java index 0a55fbe8bf75..3c6ab34733e5 100644 --- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java @@ -47,9 +47,9 @@ public class ScrimDrawable extends Drawable { private ValueAnimator mColorAnimation; private int mMainColorTo; private float mCornerRadius; - private Rect mBounds; private ConcaveInfo mConcaveInfo; private int mBottomEdgePosition; + private boolean mCornerRadiusEnabled; public ScrimDrawable() { mPaint = new Paint(); @@ -134,29 +134,50 @@ public class ScrimDrawable extends Drawable { } /** - * Enable drawable shape to have rounded corners with provided radius + * Corner radius used by either concave or convex corners. */ public void setRoundedCorners(float radius) { + if (radius == mCornerRadius) { + return; + } mCornerRadius = radius; + if (mConcaveInfo != null) { + mConcaveInfo.setCornerRadius(radius); + updatePath(); + } + invalidateSelf(); } /** - * Make bottom edge concave with provided corner radius + * If we should draw a rounded rect instead of a rect. */ - public void setBottomEdgeConcave(float radius) { - if (radius == 0) { - // Disable clipping completely when there's no radius. - mConcaveInfo = null; + public void setRoundedCornersEnabled(boolean enabled) { + if (mCornerRadiusEnabled == enabled) { + return; + } + mCornerRadiusEnabled = enabled; + invalidateSelf(); + } + + /** + * If we should draw a concave rounded rect instead of a rect. + */ + public void setBottomEdgeConcave(boolean enabled) { + if (enabled && mConcaveInfo != null) { return; } - // only rounding top corners for clip out path - float[] cornerRadii = new float[]{radius, radius, radius, radius, 0, 0, 0, 0}; - mConcaveInfo = new ConcaveInfo(radius, cornerRadii); + if (!enabled) { + mConcaveInfo = null; + } else { + mConcaveInfo = new ConcaveInfo(); + mConcaveInfo.setCornerRadius(mCornerRadius); + } + invalidateSelf(); } /** * Location of concave edge. - * @see #setBottomEdgeConcave(float) + * @see #setBottomEdgeConcave(boolean) */ public void setBottomEdgePosition(int y) { if (mBottomEdgePosition == y) { @@ -176,34 +197,35 @@ public class ScrimDrawable extends Drawable { mPaint.setAlpha(mAlpha); if (mConcaveInfo != null) { drawConcave(canvas); - } else { + } else if (mCornerRadiusEnabled && mCornerRadius > 0) { canvas.drawRoundRect(getBounds().left, getBounds().top, getBounds().right, getBounds().bottom + mCornerRadius, /* x radius*/ mCornerRadius, /* y radius*/ mCornerRadius, mPaint); + } else { + canvas.drawRect(getBounds().left, getBounds().top, getBounds().right, + getBounds().bottom, mPaint); } } + @Override + protected void onBoundsChange(Rect bounds) { + updatePath(); + } + private void drawConcave(Canvas canvas) { - // checking if width of clip out path needs to change - if (mBounds == null - || getBounds().right != mBounds.right - || getBounds().left != mBounds.left) { - mBounds = getBounds(); - updatePath(); - } canvas.clipOutPath(mConcaveInfo.mPath); canvas.drawRect(getBounds().left, getBounds().top, getBounds().right, mBottomEdgePosition + mConcaveInfo.mPathOverlap, mPaint); } private void updatePath() { - mConcaveInfo.mPath.reset(); - if (mBounds == null) { - mBounds = getBounds(); + if (mConcaveInfo == null) { + return; } + mConcaveInfo.mPath.reset(); float top = mBottomEdgePosition; float bottom = mBottomEdgePosition + mConcaveInfo.mPathOverlap; - mConcaveInfo.mPath.addRoundRect(mBounds.left, top, mBounds.right, bottom, + mConcaveInfo.mPath.addRoundRect(getBounds().left, top, getBounds().right, bottom, mConcaveInfo.mCornerRadii, Path.Direction.CW); } @@ -213,13 +235,20 @@ public class ScrimDrawable extends Drawable { } private static class ConcaveInfo { - private final float mPathOverlap; + private float mPathOverlap; private final float[] mCornerRadii; private final Path mPath = new Path(); - ConcaveInfo(float pathOverlap, float[] cornerRadii) { - mPathOverlap = pathOverlap; - mCornerRadii = cornerRadii; + ConcaveInfo() { + mCornerRadii = new float[] {0, 0, 0, 0, 0, 0, 0, 0}; + } + + public void setCornerRadius(float radius) { + mPathOverlap = radius; + mCornerRadii[0] = radius; + mCornerRadii[1] = radius; + mCornerRadii[2] = radius; + mCornerRadii[3] = radius; } } } diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java index 0d9ade6da49c..1a5c9ee25b47 100644 --- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java +++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java @@ -31,14 +31,12 @@ import android.os.Looper; import android.util.AttributeSet; import android.view.View; -import androidx.annotation.DimenRes; import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.colorextraction.ColorExtractor; -import com.android.systemui.R; import java.util.concurrent.Executor; @@ -50,9 +48,6 @@ import java.util.concurrent.Executor; */ public class ScrimView extends View { - @DimenRes - private static final int CORNER_RADIUS = R.dimen.notification_scrim_corner_radius; - private final Object mColorLock = new Object(); @GuardedBy("mColorLock") @@ -301,13 +296,10 @@ public class ScrimView extends View { * Make bottom edge concave so overlap between layers is not visible for alphas between 0 and 1 * @return height of concavity */ - public float enableBottomEdgeConcave(boolean clipScrim) { + public void enableBottomEdgeConcave(boolean clipScrim) { if (mDrawable instanceof ScrimDrawable) { - float radius = clipScrim ? getResources().getDimensionPixelSize(CORNER_RADIUS) : 0; - ((ScrimDrawable) mDrawable).setBottomEdgeConcave(radius); - return radius; + ((ScrimDrawable) mDrawable).setBottomEdgeConcave(clipScrim); } - return 0; } /** @@ -321,12 +313,11 @@ public class ScrimView extends View { } /** - * Enable view to have rounded corners with radius of {@link #CORNER_RADIUS} + * Enable view to have rounded corners. */ - public void enableRoundedCorners() { + public void enableRoundedCorners(boolean enabled) { if (mDrawable instanceof ScrimDrawable) { - int radius = getResources().getDimensionPixelSize(CORNER_RADIUS); - ((ScrimDrawable) mDrawable).setRoundedCorners(radius); + ((ScrimDrawable) mDrawable).setRoundedCornersEnabled(enabled); } } @@ -340,4 +331,15 @@ public class ScrimView extends View { mDrawableBounds.set((int) left, (int) top, (int) right, (int) bottom); mDrawable.setBounds(mDrawableBounds); } + + /** + * Corner radius of both concave or convex corners. + * @see #enableRoundedCorners(boolean) + * @see #enableBottomEdgeConcave(boolean) + */ + public void setCornerRadius(int radius) { + if (mDrawable instanceof ScrimDrawable) { + ((ScrimDrawable) mDrawable).setRoundedCorners(radius); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt index a4bb09533cd4..7c0496bd8b72 100644 --- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt @@ -16,8 +16,6 @@ package com.android.systemui.sensorprivacy -import android.app.KeyguardManager -import android.app.KeyguardManager.KeyguardDismissCallback import android.content.DialogInterface import android.content.Intent.EXTRA_PACKAGE_NAME import android.content.pm.PackageManager @@ -28,16 +26,15 @@ import android.hardware.SensorPrivacyManager.EXTRA_SENSOR import android.os.Bundle import android.os.Handler import android.text.Html -import android.util.Log import android.view.View.GONE import android.view.View.VISIBLE import android.widget.ImageView import com.android.internal.app.AlertActivity import com.android.internal.widget.DialogTitle -import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R +import com.android.systemui.statusbar.phone.KeyguardDismissUtil import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController - +import com.android.systemui.statusbar.policy.KeyguardStateController import javax.inject.Inject /** @@ -48,8 +45,8 @@ import javax.inject.Inject */ class SensorUseStartedActivity @Inject constructor( private val sensorPrivacyController: IndividualSensorPrivacyController, - private val keyguardManager: KeyguardManager, - private val keyguardUpdateMonitor: KeyguardUpdateMonitor + private val keyguardStateController: KeyguardStateController, + private val keyguardDismissUtil: KeyguardDismissUtil ) : AlertActivity(), DialogInterface.OnClickListener { companion object { @@ -180,17 +177,11 @@ class SensorUseStartedActivity @Inject constructor( override fun onClick(dialog: DialogInterface?, which: Int) { when (which) { BUTTON_POSITIVE -> { - if (keyguardUpdateMonitor.getUserHasTrust(userId)) { - keyguardManager - .requestDismissKeyguard(this, object : KeyguardDismissCallback() { - override fun onDismissError() { - Log.e(LOG_TAG, "Cannot dismiss keyguard") - } - - override fun onDismissSucceeded() { - disableSensorPrivacy() - } - }) + if (keyguardStateController.isMethodSecure && keyguardStateController.isShowing) { + keyguardDismissUtil.executeWhenUnlocked({ + disableSensorPrivacy() + false + }, false) } else { disableSensorPrivacy() } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java index 17b489ca2490..d96e1ba22ecc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java @@ -44,10 +44,6 @@ public class FeatureFlags { return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2_rendering); } - public boolean isShadeOpaque() { - return mFlagReader.isEnabled(R.bool.flag_shade_is_opaque); - } - /** b/171917882 */ public boolean isTwoColumnNotificationShadeEnabled() { return mFlagReader.isEnabled(R.bool.flag_notification_twocolumn); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index c1eaaaf92d52..6b68fc6640ee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -888,7 +888,14 @@ public class KeyguardIndicationController implements KeyguardStateController.Cal if (msgId == FaceManager.FACE_ERROR_TIMEOUT) { // The face timeout message is not very actionable, let's ask the user to // manually retry. - showSwipeUpToUnlock(); + if (!mStatusBarKeyguardViewManager.isBouncerShowing() + && mKeyguardUpdateMonitor.isUdfpsEnrolled()) { + // suggest trying fingerprint + showTransientIndication(R.string.keyguard_try_fingerprint); + } else { + // suggest swiping up to unlock (try face auth again or swipe up to bouncer) + showSwipeUpToUnlock(); + } } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) { mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState); } else if (mKeyguardUpdateMonitor.isScreenOn()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index 2a468938ecff..e8ce5f952b3b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -98,15 +98,6 @@ class NotificationShadeDepthController @Inject constructor( var globalActionsSpring = DepthAnimation() var showingHomeControls: Boolean = false - @VisibleForTesting - var brightnessMirrorSpring = DepthAnimation() - var brightnessMirrorVisible: Boolean = false - set(value) { - field = value - brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f) - else 0) - } - var qsPanelExpansion = 0f set(value) { if (field == value) return @@ -169,7 +160,6 @@ class NotificationShadeDepthController @Inject constructor( normalizedBlurRadius * ANIMATION_BLUR_FRACTION).toInt() combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsPanelExpansion)) var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius).toFloat() - shadeRadius *= 1f - brightnessMirrorSpring.ratio val launchProgress = notificationLaunchAnimationParams?.linearProgress ?: 0f shadeRadius *= (1f - launchProgress) * (1f - launchProgress) @@ -263,7 +253,6 @@ class NotificationShadeDepthController @Inject constructor( shadeSpring.finishIfRunning() shadeAnimation.finishIfRunning() globalActionsSpring.finishIfRunning() - brightnessMirrorSpring.finishIfRunning() } } @@ -425,7 +414,6 @@ class NotificationShadeDepthController @Inject constructor( it.println("shadeRadius: ${shadeSpring.radius}") it.println("shadeAnimation: ${shadeAnimation.radius}") it.println("globalActionsRadius: ${globalActionsSpring.radius}") - it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}") it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius") it.println("notificationLaunchAnimationProgress: " + "${notificationLaunchAnimationParams?.linearProgress}") diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 8264a9ce8bed..fb109f310e15 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -84,7 +84,6 @@ public class NotificationShelf extends ActivatableNotificationView implements private int mCutoutHeight; private int mGapHeight; private int mIndexOfFirstViewInShelf = -1; - private int mIndexOfFirstViewInOverflowingSection = -1; private NotificationShelfController mController; @@ -180,7 +179,6 @@ public class NotificationShelf extends ActivatableNotificationView implements viewState.xTranslation = getTranslationX(); viewState.hasItemsInStableShelf = lastViewState.inShelf; viewState.firstViewInShelf = algorithmState.firstViewInShelf; - viewState.firstViewInOverflowSection = algorithmState.firstViewInOverflowSection; if (mNotGoneIndex != -1) { viewState.notGoneIndex = Math.min(viewState.notGoneIndex, mNotGoneIndex); } @@ -268,17 +266,6 @@ public class NotificationShelf extends ActivatableNotificationView implements // TODO(b/172289889) scale mPaddingBetweenElements with expansion amount if ((isLastChild && !child.isInShelf()) || aboveShelf || backgroundForceHidden) { notificationClipEnd = stackEnd; - } else if (mAmbientState.isExpansionChanging()) { - if (mIndexOfFirstViewInOverflowingSection != -1 - && i >= mIndexOfFirstViewInOverflowingSection) { - // Clip notifications in (section overflowing into shelf) to shelf start. - notificationClipEnd = shelfStart - mPaddingBetweenElements; - } else { - // Clip notifications before the section overflowing into shelf - // to stackEnd because we do not show the shelf if the section right before the - // shelf is still hidden. - notificationClipEnd = stackEnd; - } } else { notificationClipEnd = shelfStart - mPaddingBetweenElements; } @@ -831,11 +818,6 @@ public class NotificationShelf extends ActivatableNotificationView implements mIndexOfFirstViewInShelf = mHostLayoutController.indexOfChild(firstViewInShelf); } - public void setFirstViewInOverflowingSection(ExpandableView firstViewInOverflowingSection) { - mIndexOfFirstViewInOverflowingSection = - mHostLayoutController.indexOfChild(firstViewInOverflowingSection); - } - private class ShelfState extends ExpandableViewState { private boolean hasItemsInStableShelf; private ExpandableView firstViewInShelf; @@ -849,7 +831,6 @@ public class NotificationShelf extends ActivatableNotificationView implements super.applyToView(view); setIndexOfFirstViewInShelf(firstViewInShelf); - setFirstViewInOverflowingSection(firstViewInOverflowSection); updateAppearance(); setHasItemsInStableShelf(hasItemsInStableShelf); mShelfIcons.setAnimationsEnabled(mAnimationsEnabled); @@ -863,7 +844,6 @@ public class NotificationShelf extends ActivatableNotificationView implements super.animateTo(child, properties); setIndexOfFirstViewInShelf(firstViewInShelf); - setFirstViewInOverflowingSection(firstViewInOverflowSection); updateAppearance(); setHasItemsInStableShelf(hasItemsInStableShelf); mShelfIcons.setAnimationsEnabled(mAnimationsEnabled); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt index 3bf1ff2cf7fa..91415f2788a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt @@ -34,8 +34,14 @@ import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.leak.RotationUtils import com.android.systemui.R +import com.android.systemui.util.time.SystemClock import java.io.PrintWriter import javax.inject.Inject +import kotlin.math.min +import kotlin.math.pow + +private const val MAX_DEBOUNCE_LEVEL = 3 +private const val BASE_DEBOUNCE_TIME = 2000 /*** * Controls the ripple effect that shows when wired charging begins. @@ -47,9 +53,11 @@ class WiredChargingRippleController @Inject constructor( batteryController: BatteryController, configurationController: ConfigurationController, featureFlags: FeatureFlags, - private val context: Context + private val context: Context, + private val windowManager: WindowManager, + private val systemClock: SystemClock ) { - private var charging: Boolean? = null + private var pluggedIn: Boolean? = null private val rippleEnabled: Boolean = featureFlags.isChargingRippleEnabled && !SystemProperties.getBoolean("persist.debug.suppress-charging-ripple", false) private var normalizedPortPosX: Float = context.resources.getFloat( @@ -68,6 +76,8 @@ class WiredChargingRippleController @Inject constructor( or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) setTrustedOverlay() } + private var lastTriggerTime: Long? = null + private var debounceLevel = 0 @VisibleForTesting var rippleView: ChargingRippleView = ChargingRippleView(context, attrs = null) @@ -76,19 +86,18 @@ class WiredChargingRippleController @Inject constructor( val batteryStateChangeCallback = object : BatteryController.BatteryStateChangeCallback { override fun onBatteryLevelChanged( level: Int, - pluggedIn: Boolean, - nowCharging: Boolean + nowPluggedIn: Boolean, + charging: Boolean ) { // Suppresses the ripple when it's disabled, or when the state change comes // from wireless charging. - if (!rippleEnabled || batteryController.isWirelessCharging) { + if (!rippleEnabled || batteryController.isPluggedInWireless) { return } - val wasCharging = charging - charging = nowCharging - // Only triggers when the keyguard is active and the device is just plugged in. - if ((wasCharging == null || !wasCharging) && nowCharging) { - startRipple() + val wasPluggedIn = pluggedIn + pluggedIn = nowPluggedIn + if ((wasPluggedIn == null || !wasPluggedIn) && nowPluggedIn) { + startRippleWithDebounce() } } } @@ -118,6 +127,22 @@ class WiredChargingRippleController @Inject constructor( updateRippleColor() } + // Lazily debounce ripple to avoid triggering ripple constantly (e.g. from flaky chargers). + internal fun startRippleWithDebounce() { + val now = systemClock.elapsedRealtime() + // Debounce wait time = 2 ^ debounce level + if (lastTriggerTime == null || + (now - lastTriggerTime!!) > BASE_DEBOUNCE_TIME * (2.0.pow(debounceLevel))) { + // Not waiting for debounce. Start ripple. + startRipple() + debounceLevel = 0 + } else { + // Still waiting for debounce. Ignore ripple and bump debounce level. + debounceLevel = min(MAX_DEBOUNCE_LEVEL, debounceLevel + 1) + } + lastTriggerTime = now + } + fun startRipple() { if (!rippleEnabled || rippleView.rippleInProgress || rippleView.parent != null) { // Skip if ripple is still playing, or not playing but already added the parent @@ -125,7 +150,6 @@ class WiredChargingRippleController @Inject constructor( // the animation ends.) return } - val mWM = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager windowLayoutParams.packageName = context.opPackageName rippleView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { override fun onViewDetachedFromWindow(view: View?) {} @@ -133,12 +157,12 @@ class WiredChargingRippleController @Inject constructor( override fun onViewAttachedToWindow(view: View?) { layoutRipple() rippleView.startRipple(Runnable { - mWM.removeView(rippleView) + windowManager.removeView(rippleView) }) rippleView.removeOnAttachStateChangeListener(this) } }) - mWM.addView(rippleView, windowLayoutParams) + windowManager.addView(rippleView, windowLayoutParams) } private fun layoutRipple() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt index 46a971b4cbd1..1e071312065b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt @@ -68,7 +68,7 @@ class SystemStatusAnimationScheduler @Inject constructor( } private fun isImmersiveIndicatorEnabled(): Boolean { return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_ENABLE_IMMERSIVE_INDICATOR, false) + PROPERTY_ENABLE_IMMERSIVE_INDICATOR, true) } /** True from the time a scheduled event starts until it's animation finishes */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt index d925a93d982a..c85b62fc0d9a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt @@ -84,14 +84,6 @@ class NotificationLaunchAnimatorController( notificationShadeWindowViewController.setExpandAnimationRunning(false) } - override fun onLaunchAnimationTimedOut() { - notificationShadeWindowViewController.setExpandAnimationRunning(false) - } - - override fun onLaunchAnimationAborted() { - notificationShadeWindowViewController.setExpandAnimationRunning(false) - } - override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { notification.isExpandAnimationRunning = true notificationListContainer.setExpandingNotification(notification) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt index fb42c424f603..fad0e49b3637 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.collection +import android.app.Notification import android.app.NotificationManager.IMPORTANCE_HIGH import android.app.NotificationManager.IMPORTANCE_MIN import android.service.notification.NotificationListenerService.Ranking @@ -25,6 +26,7 @@ import com.android.systemui.statusbar.NotificationMediaManager import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger import com.android.systemui.statusbar.notification.NotificationFilter import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON @@ -33,11 +35,11 @@ import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVI import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT import com.android.systemui.statusbar.notification.stack.PriorityBucket -import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy import com.android.systemui.statusbar.policy.HeadsUpManager import dagger.Lazy import java.util.Objects import javax.inject.Inject +import kotlin.Comparator private const val TAG = "NotifRankingManager" @@ -77,6 +79,9 @@ open class NotificationRankingManager @Inject constructor( val aIsFsn = a.isColorizedForegroundService() val bIsFsn = b.isColorizedForegroundService() + val aCall = a.isImportantCall() + val bCall = b.isImportantCall() + val aPersonType = a.getPeopleNotificationType() val bPersonType = b.getPeopleNotificationType() @@ -96,6 +101,7 @@ open class NotificationRankingManager @Inject constructor( // Provide consistent ranking with headsUpManager aHeadsUp -> headsUpManager.compare(a, b) aIsFsn != bIsFsn -> if (aIsFsn) -1 else 1 + aCall != bCall -> if (aCall) -1 else 1 usePeopleFiltering && aPersonType != bPersonType -> peopleNotificationIdentifier.compareTo(aPersonType, bPersonType) // Upsort current media notification. @@ -150,11 +156,12 @@ open class NotificationRankingManager @Inject constructor( @PriorityBucket private fun getBucketForEntry(entry: NotificationEntry): Int { + val isImportantCall = entry.isImportantCall() val isHeadsUp = entry.isRowHeadsUp val isMedia = entry.isImportantMedia() val isSystemMax = entry.isSystemMax() return when { - entry.isColorizedForegroundService() -> BUCKET_FOREGROUND_SERVICE + entry.isColorizedForegroundService() || isImportantCall -> BUCKET_FOREGROUND_SERVICE usePeopleFiltering && entry.isConversation() -> BUCKET_PEOPLE isHeadsUp || isMedia || isSystemMax || entry.isHighPriority() -> BUCKET_ALERTING else -> BUCKET_SILENT @@ -186,7 +193,7 @@ open class NotificationRankingManager @Inject constructor( } private fun NotificationEntry.isImportantMedia() = - key == mediaManager.mediaNotificationKey && ranking.importance > IMPORTANCE_MIN + key == mediaManager.mediaNotificationKey && importance > IMPORTANCE_MIN private fun NotificationEntry.isConversation() = getPeopleNotificationType() != TYPE_NON_PERSON @@ -204,6 +211,10 @@ private fun NotificationEntry.isSystemMax() = private fun StatusBarNotification.isSystemNotification() = "android" == packageName || "com.android.systemui" == packageName +private fun NotificationEntry.isImportantCall() = + sbn.notification.extras?.getString(Notification.EXTRA_TEMPLATE) == + "android.app.Notification\$CallStyle" && importance > IMPORTANCE_MIN + private fun NotificationEntry.isColorizedForegroundService() = sbn.notification.run { isForegroundService && isColorized && importance > IMPORTANCE_MIN } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java index 9e70f0ac29d5..caba3ac7e17b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java @@ -37,8 +37,9 @@ public class HybridConversationNotificationView extends HybridNotificationView { private ImageView mConversationIconView; private TextView mConversationSenderName; private View mConversationFacePile; - private int mConversationIconSize; + private int mSingleAvatarSize; private int mFacePileSize; + private int mFacePileAvatarSize; private int mFacePileProtectionWidth; public HybridConversationNotificationView(Context context) { @@ -67,7 +68,9 @@ public class HybridConversationNotificationView extends HybridNotificationView { mConversationSenderName = requireViewById(R.id.conversation_notification_sender); mFacePileSize = getResources() .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_size); - mConversationIconSize = getResources() + mFacePileAvatarSize = getResources() + .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_avatar_size); + mSingleAvatarSize = getResources() .getDimensionPixelSize(R.dimen.conversation_single_line_avatar_size); mFacePileProtectionWidth = getResources().getDimensionPixelSize( R.dimen.conversation_single_line_face_pile_protection_width); @@ -89,6 +92,7 @@ public class HybridConversationNotificationView extends HybridNotificationView { mConversationFacePile.setVisibility(GONE); mConversationIconView.setVisibility(VISIBLE); mConversationIconView.setImageIcon(conversationIcon); + setSize(mConversationIconView, mSingleAvatarSize); } else { // If there isn't an icon, generate a "face pile" based on the sender avatars mConversationIconView.setVisibility(GONE); @@ -104,9 +108,9 @@ public class HybridConversationNotificationView extends HybridNotificationView { com.android.internal.R.id.conversation_face_pile_top); conversationLayout.bindFacePile(facePileBottomBg, facePileBottom, facePileTop); setSize(mConversationFacePile, mFacePileSize); - setSize(facePileBottom, mConversationIconSize); - setSize(facePileTop, mConversationIconSize); - setSize(facePileBottomBg, mConversationIconSize + 2 * mFacePileProtectionWidth); + setSize(facePileBottom, mFacePileAvatarSize); + setSize(facePileTop, mFacePileAvatarSize); + setSize(facePileBottomBg, mFacePileAvatarSize + 2 * mFacePileProtectionWidth); mTransformationHelper.addViewTransformingToSimilar(facePileTop); mTransformationHelper.addViewTransformingToSimilar(facePileBottom); mTransformationHelper.addViewTransformingToSimilar(facePileBottomBg); 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 884ad8d5cee4..fe4ea28b1ed0 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 @@ -1258,7 +1258,7 @@ public class NotificationContentView extends FrameLayout { RemoteInputView riv = RemoteInputView.inflate( mContext, actionContainer, entry, mRemoteInputController); - riv.setVisibility(View.INVISIBLE); + riv.setVisibility(View.GONE); actionContainer.addView(riv, new LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java index 15ca24edc996..8ee91342daed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java @@ -20,14 +20,12 @@ import static com.android.systemui.statusbar.notification.TransformState.TRANSFO import android.app.Notification; import android.content.Context; -import android.content.res.ColorStateList; import android.util.ArraySet; import android.util.Pair; import android.view.NotificationHeaderView; import android.view.NotificationTopLineView; import android.view.View; import android.view.ViewGroup; -import android.view.ViewGroup.MarginLayoutParams; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import android.widget.ImageButton; @@ -168,53 +166,6 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { } } - public void applyConversationSkin() { - if (mAppNameText != null) { - final ColorStateList colors = mAppNameText.getTextColors(); - mAppNameText.setTextAppearance( - com.android.internal.R.style - .TextAppearance_DeviceDefault_Notification_Conversation_AppName); - mAppNameText.setTextColor(colors); - MarginLayoutParams layoutParams = (MarginLayoutParams) mAppNameText.getLayoutParams(); - layoutParams.setMarginStart(0); - } - if (mNotificationTopLine != null) { - int paddingStart = mNotificationTopLine.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.conversation_content_start); - mNotificationTopLine.setPaddingStart(paddingStart); - } - if (mIcon != null) { - MarginLayoutParams layoutParams = (MarginLayoutParams) mIcon.getLayoutParams(); - int marginStart = mIcon.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.conversation_icon_circle_start); - layoutParams.setMarginStart(marginStart); - } - } - - public void clearConversationSkin() { - if (mAppNameText != null) { - final ColorStateList colors = mAppNameText.getTextColors(); - mAppNameText.setTextAppearance( - com.android.internal.R.style.TextAppearance_DeviceDefault_Notification_Info); - mAppNameText.setTextColor(colors); - MarginLayoutParams layoutParams = (MarginLayoutParams) mAppNameText.getLayoutParams(); - final int marginStart = mAppNameText.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.notification_header_app_name_margin_start); - layoutParams.setMarginStart(marginStart); - } - if (mNotificationTopLine != null) { - int paddingStart = mNotificationTopLine.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.notification_content_margin_start); - mNotificationTopLine.setPaddingStart(paddingStart); - } - if (mIcon != null) { - MarginLayoutParams layoutParams = (MarginLayoutParams) mIcon.getLayoutParams(); - int marginStart = mIcon.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.notification_icon_circle_start); - layoutParams.setMarginStart(marginStart); - } - } - /** * Adds the remaining TransformTypes to the TransformHelper. This is done to make sure that each * child is faded automatically and doesn't have to be manually added. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java index 040f707e12f1..0247a99bc6c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaHeaderView.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.stack; import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.util.AttributeSet; -import android.view.ViewGroup; import com.android.systemui.statusbar.notification.row.ExpandableView; @@ -43,11 +42,4 @@ public class MediaHeaderView extends ExpandableView { public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) { // No animation, it doesn't need it, this would be local } - - public void setContentView(ViewGroup contentView) { - addView(contentView); - ViewGroup.LayoutParams layoutParams = contentView.getLayoutParams(); - layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; - layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 5f3933b827c4..99fe541d0135 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -43,7 +43,6 @@ import com.android.systemui.statusbar.notification.collection.legacy.VisualStabi import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.HybridGroupManager; import com.android.systemui.statusbar.notification.row.HybridNotificationView; -import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import java.util.ArrayList; @@ -336,15 +335,6 @@ public class NotificationChildrenContainer extends ViewGroup { } mNotificationHeaderWrapper.setExpanded(mChildrenExpanded); mNotificationHeaderWrapper.onContentUpdated(mContainingNotification); - if (mNotificationHeaderWrapper instanceof NotificationHeaderViewWrapper) { - NotificationHeaderViewWrapper headerWrapper = - (NotificationHeaderViewWrapper) mNotificationHeaderWrapper; - if (isConversation) { - headerWrapper.applyConversationSkin(); - } else { - headerWrapper.clearConversationSkin(); - } - } recreateLowPriorityHeader(builder, isConversation); updateHeaderVisibility(false /* animate */); updateChildrenAppearance(); @@ -378,15 +368,6 @@ public class NotificationChildrenContainer extends ViewGroup { header.reapply(getContext(), mNotificationHeaderLowPriority); } mNotificationHeaderWrapperLowPriority.onContentUpdated(mContainingNotification); - if (mNotificationHeaderWrapper instanceof NotificationHeaderViewWrapper) { - NotificationHeaderViewWrapper headerWrapper = - (NotificationHeaderViewWrapper) mNotificationHeaderWrapper; - if (isConversation) { - headerWrapper.applyConversationSkin(); - } else { - headerWrapper.clearConversationSkin(); - } - } resetHeaderVisibilityIfNeeded(mNotificationHeaderLowPriority, calculateDesiredHeader()); } else { removeView(mNotificationHeaderLowPriority); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt index b06f7d25db16..45ce20a1f08f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt @@ -138,7 +138,7 @@ class NotificationSectionsManager @Inject internal constructor( incomingHeaderController.reinflateView(parent) mediaControlsView = reinflateView(mediaControlsView, layoutInflater, R.layout.keyguard_media_header) - .also(keyguardMediaController::attach) + keyguardMediaController.attachSinglePaneContainer(mediaControlsView) } override fun beginsSection(view: View, previous: View?): Boolean = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 751573ac2cca..b81619317b95 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -431,6 +431,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private DismissAllAnimationListener mDismissAllAnimationListener; private NotificationRemoteInputManager mRemoteInputManager; private ShadeController mShadeController; + private Runnable mOnStackYChanged; private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class); private final LockscreenGestureLogger mLockscreenGestureLogger = @@ -1142,14 +1143,22 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable */ private void updateStackPosition() { // Consider interpolating from an mExpansionStartY for use on lockscreen and AOD - mAmbientState.setStackY( - MathUtils.lerp(0, mTopPadding, mAmbientState.getExpansionFraction())); + final float stackY = MathUtils.lerp(0, mTopPadding, mAmbientState.getExpansionFraction()); + mAmbientState.setStackY(stackY); + if (mOnStackYChanged != null) { + mOnStackYChanged.run(); + } + final float shadeBottom = getHeight() - getEmptyBottomMargin(); mAmbientState.setStackEndHeight(shadeBottom - mTopPadding); mAmbientState.setStackHeight( MathUtils.lerp(0, shadeBottom - mTopPadding, mAmbientState.getExpansionFraction())); } + void setOnStackYChanged(Runnable onStackYChanged) { + mOnStackYChanged = onStackYChanged; + } + /** * Update the height of the panel. * @@ -4533,7 +4542,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable // We still want to call the normal scrolled changed for accessibility reasons onScrollChanged(mScrollX, ownScrollY, mScrollX, mOwnScrollY); mOwnScrollY = ownScrollY; + updateChildren(); updateOnScrollChange(); + updateStackPosition(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 36a370c71216..ae9467eb651b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -708,9 +708,10 @@ public class NotificationStackScrollLayoutController { mView.setKeyguardMediaControllorVisible(visible); if (visible) { mView.generateAddAnimation( - mKeyguardMediaController.getView(), false /*fromMoreCard */); + mKeyguardMediaController.getSinglePaneContainer(), + false /*fromMoreCard */); } else { - mView.generateRemoveAnimation(mKeyguardMediaController.getView()); + mView.generateRemoveAnimation(mKeyguardMediaController.getSinglePaneContainer()); } mView.requestChildrenUpdate(); return Unit.INSTANCE; @@ -970,6 +971,10 @@ public class NotificationStackScrollLayoutController { mView.setQsExpansionFraction(expansionFraction); } + public void setOnStackYChanged(Runnable onStackYChanged) { + mView.setOnStackYChanged(onStackYChanged); + } + public float calculateAppearFractionBypass() { return mView.calculateAppearFractionBypass(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 6cacec71db39..7d586ba3cbce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -33,9 +33,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.row.FooterView; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * The Algorithm of the {@link com.android.systemui.statusbar.notification.stack @@ -153,9 +151,8 @@ public class StackScrollAlgorithm { private void updateClipping(StackScrollAlgorithmState algorithmState, AmbientState ambientState) { - float drawStart = !ambientState.isOnKeyguard() ? ambientState.getTopPadding() - + ambientState.getStackTranslation() - : 0; + float drawStart = !ambientState.isOnKeyguard() + ? ambientState.getStackY() - ambientState.getScrollY() : 0; float clipStart = 0; int childCount = algorithmState.visibleChildren.size(); boolean firstHeadsUp = true; @@ -168,8 +165,7 @@ public class StackScrollAlgorithm { float newYTranslation = state.yTranslation; float newHeight = state.height; float newNotificationEnd = newYTranslation + newHeight; - boolean isHeadsUp = (child instanceof ExpandableNotificationRow) - && ((ExpandableNotificationRow) child).isPinned(); + boolean isHeadsUp = (child instanceof ExpandableNotificationRow) && child.isPinned(); if (mClipNotificationScrollToTop && (!state.inShelf || (isHeadsUp && !firstHeadsUp)) && newYTranslation < clipStart @@ -255,16 +251,16 @@ public class StackScrollAlgorithm { } } - state.firstViewInShelf = null; - // Save y, sectionStart, sectionEnd from when shade is fully expanded. - // Consider updating these states in updateContentView instead so that we don't have to - // recalculate in every frame. + // Save (height of view before shelf, index of first view in shelf) from when shade is fully + // expanded. Consider updating these states in updateContentView instead so that we don't + // have to recalculate in every frame. float currentY = -scrollY; - int sectionStartIndex = 0; - int sectionEndIndex = 0; + float previousY = 0; + state.firstViewInShelf = null; + state.viewHeightBeforeShelf = -1; for (int i = 0; i < state.visibleChildren.size(); i++) { final ExpandableView view = state.visibleChildren.get(i); - // Add space between sections. + final boolean applyGapHeight = childNeedsGapHeight( ambientState.getSectionProvider(), i, view, getPreviousView(i, state)); @@ -273,88 +269,27 @@ public class StackScrollAlgorithm { } if (ambientState.getShelf() != null) { - // Save index of first view in the shelf final float shelfStart = ambientState.getStackEndHeight() - ambientState.getShelf().getIntrinsicHeight(); if (currentY >= shelfStart && !(view instanceof FooterView) && state.firstViewInShelf == null) { state.firstViewInShelf = view; + // There might be a section gap right before the shelf. + // Limit the height of the view before the shelf so that it does not include + // a gap and become taller than it normally is. + state.viewHeightBeforeShelf = Math.min(getMaxAllowedChildHeight(view), + ambientState.getStackEndHeight() + - ambientState.getShelf().getIntrinsicHeight() + - mPaddingBetweenElements + - previousY); } } - - // Record y position when fully expanded - ExpansionData expansionData = new ExpansionData(); - expansionData.fullyExpandedY = currentY; - state.expansionData.put(view, expansionData); - - if (ambientState.getSectionProvider() - .beginsSection(view, getPreviousView(i, state))) { - - // Save section start/end for views in the section before this new section - ExpandableView sectionStartView = state.visibleChildren.get(sectionStartIndex); - final float sectionStart = - state.expansionData.get(sectionStartView).fullyExpandedY; - - ExpandableView sectionEndView = state.visibleChildren.get(sectionEndIndex); - float sectionEnd = state.expansionData.get(sectionEndView).fullyExpandedY - + sectionEndView.getIntrinsicHeight(); - - if (ambientState.getShelf() != null) { - // If we show the shelf, trim section end to shelf start - // This means section end > start for views in the shelf - final float shelfStart = ambientState.getStackEndHeight() - - ambientState.getShelf().getIntrinsicHeight(); - if (state.firstViewInShelf != null && sectionEnd > shelfStart) { - sectionEnd = shelfStart; - } - } - - // Update section bounds of every view in the previous section - // Consider using shared SectionInfo for views in same section to avoid looping back - for (int j = sectionStartIndex; j < i; j++) { - ExpandableView sectionView = state.visibleChildren.get(j); - ExpansionData viewExpansionData = - state.expansionData.get(sectionView); - viewExpansionData.sectionStart = sectionStart; - viewExpansionData.sectionEnd = sectionEnd; - state.expansionData.put(sectionView, viewExpansionData); - } - sectionStartIndex = i; - - if (view instanceof FooterView) { - // Also record section bounds for FooterView (same as its own) - // because it is the last view and we won't get to this point again - // after the loop ends - ExpansionData footerExpansionData = state.expansionData.get(view); - footerExpansionData.sectionStart = expansionData.fullyExpandedY; - footerExpansionData.sectionEnd = expansionData.fullyExpandedY - + view.getIntrinsicHeight(); - state.expansionData.put(view, footerExpansionData); - } - } - sectionEndIndex = i; + previousY = currentY; currentY = currentY + getMaxAllowedChildHeight(view) + mPaddingBetweenElements; } - - // Which view starts the section of the view right before the shelf? - // Save it for later when we clip views in that section to shelf start. - state.firstViewInOverflowSection = null; - if (state.firstViewInShelf != null) { - ExpandableView nextView = null; - final int startIndex = state.visibleChildren.indexOf(state.firstViewInShelf); - for (int i = startIndex - 1; i >= 0; i--) { - ExpandableView view = state.visibleChildren.get(i); - if (nextView != null && ambientState.getSectionProvider() - .beginsSection(nextView, view)) { - break; - } - nextView = view; - } - state.firstViewInOverflowSection = nextView; - } } private int updateNotGoneIndex(StackScrollAlgorithmState state, int notGoneIndex, @@ -394,6 +329,26 @@ public class StackScrollAlgorithm { } } + /** + * @return Fraction to apply to view height and gap between views. + * Does not include shelf height even if shelf is showing. + */ + private float getExpansionFractionWithoutShelf( + StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { + + final boolean isShowingShelf = ambientState.getShelf() != null + && algorithmState.firstViewInShelf != null; + + final float stackHeight = ambientState.getStackHeight() + - (isShowingShelf ? ambientState.getShelf().getIntrinsicHeight() : 0f); + + float stackEndHeight = ambientState.getStackEndHeight() + - (isShowingShelf ? ambientState.getShelf().getIntrinsicHeight() : 0f); + + return stackHeight / stackEndHeight; + } + // TODO(b/172289889) polish shade open from HUN /** * Populates the {@link ExpandableViewState} for a single child. @@ -426,22 +381,8 @@ public class StackScrollAlgorithm { viewState.headsUpIsVisible = end < ambientState.getMaxHeadsUpTranslation(); } - // TODO(b/172289889) move sectionFraction and showSection to initAlgorithmState - // Get fraction of section showing, and later apply it to view height and gaps between views - float sectionFraction = 1f; - boolean showSection = true; - - if (!ambientState.isOnKeyguard() - && !ambientState.isPulseExpanding() - && ambientState.isExpansionChanging()) { - - final ExpansionData expansionData = algorithmState.expansionData.get(view); - final float sectionHeight = expansionData.sectionEnd - expansionData.sectionStart; - sectionFraction = MathUtils.constrain( - (ambientState.getStackHeight() - expansionData.sectionStart) / sectionHeight, - 0f, 1f); - showSection = expansionData.sectionStart < ambientState.getStackHeight(); - } + final float expansionFraction = getExpansionFractionWithoutShelf( + algorithmState, ambientState); // Add gap between sections. final boolean applyGapHeight = @@ -449,46 +390,58 @@ public class StackScrollAlgorithm { ambientState.getSectionProvider(), i, view, getPreviousView(i, algorithmState)); if (applyGapHeight) { - currentYPosition += sectionFraction * mGapHeight; + currentYPosition += expansionFraction * mGapHeight; } viewState.yTranslation = currentYPosition; - if (view instanceof SectionHeaderView) { // Add padding before sections for overscroll effect. - viewState.yTranslation += ambientState.getSectionPadding(); + viewState.yTranslation += expansionFraction * ambientState.getSectionPadding(); } - if (view != ambientState.getTrackedHeadsUpRow()) { + if (view instanceof FooterView) { + viewState.yTranslation = Math.min(viewState.yTranslation, + ambientState.getStackHeight()); + // Hide footer if shelf is showing + viewState.hidden = algorithmState.firstViewInShelf != null; + } else if (view != ambientState.getTrackedHeadsUpRow()) { if (ambientState.isExpansionChanging()) { - viewState.hidden = !showSection; + // Show all views. Views below the shelf will later be clipped (essentially hidden) + // in NotificationShelf. + viewState.hidden = false; viewState.inShelf = algorithmState.firstViewInShelf != null && i >= algorithmState.visibleChildren.indexOf( - algorithmState.firstViewInShelf) - && !(view instanceof FooterView); + algorithmState.firstViewInShelf); } else if (ambientState.getShelf() != null) { // When pulsing (incoming notification on AOD), innerHeight is 0; clamp all // to shelf start, thereby hiding all notifications (except the first one, which we // later unhide in updatePulsingState) final int shelfStart = ambientState.getInnerHeight() - ambientState.getShelf().getIntrinsicHeight(); - if (!(view instanceof FooterView)) { - viewState.yTranslation = Math.min(viewState.yTranslation, shelfStart); - } + viewState.yTranslation = Math.min(viewState.yTranslation, shelfStart); if (viewState.yTranslation >= shelfStart) { viewState.hidden = !view.isExpandAnimationRunning() - && !view.hasExpandingChild() - && !(view instanceof FooterView); + && !view.hasExpandingChild(); viewState.inShelf = true; // Notifications in the shelf cannot be visible HUNs. viewState.headsUpIsVisible = false; } } - viewState.height = (int) MathUtils.lerp( - 0, getMaxAllowedChildHeight(view), sectionFraction); + + // Clip height of view right before shelf. + float maxViewHeight = getMaxAllowedChildHeight(view); + if (ambientState.isExpansionChanging() + && algorithmState.viewHeightBeforeShelf != -1) { + final int indexOfFirstViewInShelf = algorithmState.visibleChildren.indexOf( + algorithmState.firstViewInShelf); + if (i == indexOfFirstViewInShelf - 1) { + maxViewHeight = algorithmState.viewHeightBeforeShelf; + } + } + viewState.height = (int) MathUtils.lerp(0, maxViewHeight, expansionFraction); } - currentYPosition += viewState.height + sectionFraction * mPaddingBetweenElements; + currentYPosition += viewState.height + expansionFraction * mPaddingBetweenElements; setLocation(view.getViewState(), currentYPosition, i); viewState.yTranslation += ambientState.getStackY(); return currentYPosition; @@ -743,35 +696,6 @@ public class StackScrollAlgorithm { this.mIsExpanded = isExpanded; } - /** - * Data used to layout views while shade expansion changes. - */ - public class ExpansionData { - - /** - * Y position of top of first view in section. - */ - public float sectionStart; - - /** - * Y position of bottom of last view in section. - */ - public float sectionEnd; - - /** - * Y position of view when shade is fully expanded. - * Does not include distance between top notifications panel and top of screen. - */ - public float fullyExpandedY; - - /** - * Whether this notification is in the same section as the notification right before the - * shelf. Used to determine which notification should be clipped to shelf start while - * shade expansion changes. - */ - public boolean inOverflowingSection; - } - public class StackScrollAlgorithmState { /** @@ -785,16 +709,9 @@ public class StackScrollAlgorithm { public ExpandableView firstViewInShelf; /** - * First view in section overflowing into shelf while shade expansion changes. - */ - public ExpandableView firstViewInOverflowSection; - - /** - * Map of view to ExpansionData used for layout during shade expansion. - * Use view instead of index as key, because visibleChildren indices do not match the ones - * used in the shelf. + * Height of view right before the shelf. */ - public Map<ExpandableView, ExpansionData> expansionData = new HashMap<>(); + public float viewHeightBeforeShelf; /** * The children from the host view which are not gone. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 86ef0a727831..01d489f91de2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -39,6 +39,8 @@ import com.android.systemui.tuner.TunerService; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.HashSet; +import java.util.Set; import javax.inject.Inject; @@ -62,6 +64,8 @@ public class DozeParameters implements TunerService.Tunable, private final BatteryController mBatteryController; private final FeatureFlags mFeatureFlags; + private final Set<Callback> mCallbacks = new HashSet<>(); + private boolean mDozeAlwaysOn; private boolean mControlScreenOffAnimation; @@ -250,9 +254,26 @@ public class DozeParameters implements TunerService.Tunable, return mResources.getBoolean(R.bool.doze_long_press_uses_prox); } + /** + * Callback to listen for DozeParameter changes. + */ + public void addCallback(Callback callback) { + mCallbacks.add(callback); + } + + /** + * Remove callback that listens for DozeParameter changes. + */ + public void removeCallback(Callback callback) { + mCallbacks.remove(callback); + } + @Override public void onTuningChanged(String key, String newValue) { mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT); + for (Callback callback : mCallbacks) { + callback.onAlwaysOnChange(); + } } @Override @@ -270,4 +291,11 @@ public class DozeParameters implements TunerService.Tunable, pw.print("getSelectivelyRegisterSensorsUsingProx(): "); pw.println(getSelectivelyRegisterSensorsUsingProx()); } + + interface Callback { + /** + * Invoked when the value of getAlwaysOn may have changed. + */ + void onAlwaysOnChange(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt index 30d9841e41ee..26c6fe980ee1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt @@ -217,7 +217,7 @@ open class KeyguardBypassController : Dumpable { } companion object { - const val BYPASS_PANEL_FADE_DURATION = 67 + const val BYPASS_FADE_DURATION = 67 private const val FACE_UNLOCK_BYPASS_NO_OVERRIDE = 0 private const val FACE_UNLOCK_BYPASS_ALWAYS = 1 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index 481b2db16964..069c19770aef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -155,6 +155,8 @@ public class KeyguardClockPositionAlgorithm { private int mLockScreenMode; + private boolean mIsSplitShade; + /** * Refreshes the dimension values. */ @@ -180,7 +182,7 @@ public class KeyguardClockPositionAlgorithm { int keyguardStatusHeight, int userSwitchHeight, int clockPreferredY, int userSwitchPreferredY, boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount, boolean bypassEnabled, int unlockedStackScrollerPadding, - float qsExpansion, int cutoutTopInset) { + float qsExpansion, int cutoutTopInset, boolean isSplitShade) { mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding, userSwitchHeight); mMaxShadeBottom = maxShadeBottom; @@ -199,6 +201,7 @@ public class KeyguardClockPositionAlgorithm { mUnlockedStackScrollerPadding = unlockedStackScrollerPadding; mQsExpansion = qsExpansion; mCutoutTopInset = cutoutTopInset; + mIsSplitShade = isSplitShade; } public void run(Result result) { @@ -208,14 +211,23 @@ public class KeyguardClockPositionAlgorithm { result.clockYFullyDozing = getClockY( 1.0f /* panelExpansion */, 1.0f /* darkAmount */); result.clockAlpha = getClockAlpha(y); - result.stackScrollerPadding = mBypassEnabled ? mUnlockedStackScrollerPadding - : y + mKeyguardStatusHeight; + result.stackScrollerPadding = getStackScrollerPadding(y); result.stackScrollerPaddingExpanded = mBypassEnabled ? mUnlockedStackScrollerPadding : getClockY(1.0f, mDarkAmount) + mKeyguardStatusHeight; result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount); result.clockScale = interpolate(getBurnInScale(), 1.0f, 1.0f - mDarkAmount); } + private int getStackScrollerPadding(int clockYPosition) { + if (mBypassEnabled) { + return mUnlockedStackScrollerPadding; + } else if (mIsSplitShade) { + return clockYPosition; + } else { + return clockYPosition + mKeyguardStatusHeight; + } + } + /** * Update lock screen mode for testing different layouts */ @@ -232,15 +244,11 @@ public class KeyguardClockPositionAlgorithm { return mHeight / 2 - mKeyguardStatusHeight - mClockNotificationsMargin; } - private int getPreferredClockY() { - return mClockPreferredY; - } - private int getExpandedPreferredClockY() { if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) { return mMinTopMargin + mUserSwitchHeight; } - return (mHasCustomClock && (!mHasVisibleNotifs || mBypassEnabled)) ? getPreferredClockY() + return (mHasCustomClock && (!mHasVisibleNotifs || mBypassEnabled)) ? mClockPreferredY : getExpandedClockPosition(); } @@ -271,7 +279,7 @@ public class KeyguardClockPositionAlgorithm { private int getClockY(float panelExpansion, float darkAmount) { // Dark: Align the bottom edge of the clock at about half of the screen: - float clockYDark = (mHasCustomClock ? getPreferredClockY() : getMaxClockY()) + float clockYDark = (mHasCustomClock ? mClockPreferredY : getMaxClockY()) + burnInPreventionOffsetY(); clockYDark = MathUtils.max(0, clockYDark); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index 16f36b7b6b7e..5168533cd2b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -16,127 +16,25 @@ package com.android.systemui.statusbar.phone; -import static com.android.systemui.DejankUtils.whitelistIpcs; - import android.content.Context; -import android.os.UserManager; import android.text.TextUtils; import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.Button; import android.widget.FrameLayout; -import com.android.systemui.Dependency; -import com.android.systemui.Prefs; -import com.android.systemui.Prefs.Key; import com.android.systemui.R; -import com.android.systemui.plugins.qs.DetailAdapter; -import com.android.systemui.qs.QSDetailDisplayer; -import com.android.systemui.statusbar.policy.UserSwitcherController; /** * Container for image of the multi user switcher (tappable). */ -public class MultiUserSwitch extends FrameLayout implements View.OnClickListener { - - protected QSDetailDisplayer mQSDetailDisplayer; - private UserSwitcherController.BaseUserAdapter mUserListener; - - final UserManager mUserManager; - - - protected UserSwitcherController mUserSwitcherController; - +public class MultiUserSwitch extends FrameLayout { public MultiUserSwitch(Context context, AttributeSet attrs) { super(context, attrs); - mUserManager = UserManager.get(getContext()); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - setOnClickListener(this); - refreshContentDescription(); - } - - /** */ - public void setQSDetailDisplayer(QSDetailDisplayer detailDisplayer) { - mQSDetailDisplayer = detailDisplayer; - setUserSwitcherController(Dependency.get(UserSwitcherController.class)); - } - - public boolean hasMultipleUsers() { - if (mUserListener == null) { - return false; - } - return mUserListener.getUserCount() != 0 - && Prefs.getBoolean(getContext(), Key.SEEN_MULTI_USER, false); - } - - public void setUserSwitcherController(UserSwitcherController userSwitcherController) { - mUserSwitcherController = userSwitcherController; - registerListener(); - refreshContentDescription(); - } - - public boolean isMultiUserEnabled() { - // TODO(b/138661450) Move IPC calls to background - return whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled( - mContext.getResources().getBoolean(R.bool.qs_show_user_switcher_for_single_user))); } - private void registerListener() { - if (mUserManager.isUserSwitcherEnabled() && mUserListener == null) { - - final UserSwitcherController controller = mUserSwitcherController; - if (controller != null) { - mUserListener = new UserSwitcherController.BaseUserAdapter(controller) { - @Override - public void notifyDataSetChanged() { - refreshContentDescription(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - return null; - } - }; - refreshContentDescription(); - } - } - } - - @Override - public void onClick(View v) { - if (mQSDetailDisplayer != null && mUserSwitcherController != null) { - View center = getChildCount() > 0 ? getChildAt(0) : this; - - int[] tmpInt = new int[2]; - center.getLocationInWindow(tmpInt); - tmpInt[0] += center.getWidth() / 2; - tmpInt[1] += center.getHeight() / 2; - - mQSDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]); - } - } - - @Override - public void setClickable(boolean clickable) { - super.setClickable(clickable); - refreshContentDescription(); - } - - private void refreshContentDescription() { - String currentUser = null; - // TODO(b/138661450) - if (whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled()) - && mUserSwitcherController != null) { - currentUser = mUserSwitcherController.getCurrentUserName(mContext); - } - + void refreshContentDescription(String currentUser) { String text = null; if (!TextUtils.isEmpty(currentUser)) { @@ -166,8 +64,4 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener public boolean hasOverlappingRendering() { return false; } - - protected DetailAdapter getUserDetailAdapter() { - return mUserSwitcherController.mUserDetailAdapter; - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java new file mode 100644 index 000000000000..f27c7d28df44 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import static com.android.systemui.DejankUtils.whitelistIpcs; + +import android.os.UserManager; +import android.view.View; +import android.view.ViewGroup; + +import com.android.systemui.R; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.qs.DetailAdapter; +import com.android.systemui.qs.QSDetailDisplayer; +import com.android.systemui.qs.dagger.QSScope; +import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; + +/** View Controller for {@link MultiUserSwitch}. */ +@QSScope +public class MultiUserSwitchController extends ViewController<MultiUserSwitch> { + private final UserManager mUserManager; + private final UserSwitcherController mUserSwitcherController; + private final QSDetailDisplayer mQsDetailDisplayer; + private final FalsingManager mFalsingManager; + + private UserSwitcherController.BaseUserAdapter mUserListener; + + private final View.OnClickListener mOnClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { + return; + } + + View center = mView.getChildCount() > 0 ? mView.getChildAt(0) : mView; + + int[] tmpInt = new int[2]; + center.getLocationInWindow(tmpInt); + tmpInt[0] += center.getWidth() / 2; + tmpInt[1] += center.getHeight() / 2; + + mQsDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]); + } + }; + + @Inject + public MultiUserSwitchController(MultiUserSwitch view, UserManager userManager, + UserSwitcherController userSwitcherController, QSDetailDisplayer qsDetailDisplayer, + FalsingManager falsingManager) { + super(view); + mUserManager = userManager; + mUserSwitcherController = userSwitcherController; + mQsDetailDisplayer = qsDetailDisplayer; + mFalsingManager = falsingManager; + } + + @Override + protected void onInit() { + registerListener(); + mView.refreshContentDescription(getCurrentUser()); + } + + @Override + protected void onViewAttached() { + mView.setOnClickListener(mOnClickListener); + } + + @Override + protected void onViewDetached() { + mView.setOnClickListener(null); + } + + protected DetailAdapter getUserDetailAdapter() { + return mUserSwitcherController.mUserDetailAdapter; + } + + private void registerListener() { + if (mUserManager.isUserSwitcherEnabled() && mUserListener == null) { + + final UserSwitcherController controller = mUserSwitcherController; + if (controller != null) { + mUserListener = new UserSwitcherController.BaseUserAdapter(controller) { + @Override + public void notifyDataSetChanged() { + mView.refreshContentDescription(getCurrentUser()); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + return null; + } + }; + mView.refreshContentDescription(getCurrentUser()); + } + } + } + + private String getCurrentUser() { + // TODO(b/138661450) + if (whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled())) { + return mUserSwitcherController.getCurrentUserName(); + } + + return null; + } + + /** Returns true if view should be made visible. */ + public boolean isMultiUserEnabled() { + // TODO(b/138661450) Move IPC calls to background + return whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled( + getResources().getBoolean(R.bool.qs_show_user_switcher_for_single_user))); + } + +} 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 e2af940e66a7..c79e503379bd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -28,6 +28,7 @@ import static com.android.systemui.classifier.Classifier.QS_COLLAPSE; import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL; +import static com.android.systemui.util.Utils.shouldUseSplitNotificationShade; import static java.lang.Float.isNaN; @@ -53,6 +54,7 @@ import android.os.Bundle; import android.os.PowerManager; import android.os.SystemClock; import android.os.UserManager; +import android.os.VibrationEffect; import android.service.quickaccesswallet.QuickAccessWalletClient; import android.util.Log; import android.util.MathUtils; @@ -98,9 +100,11 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeLog; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentHostManager.FragmentListener; +import com.android.systemui.media.KeyguardMediaController; import com.android.systemui.media.MediaDataManager; import com.android.systemui.media.MediaHierarchyManager; import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.FalsingManager.FalsingTapListener; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -206,6 +210,7 @@ public class NotificationPanelViewController extends PanelViewController { private final ExpansionCallback mExpansionCallback = new ExpansionCallback(); private final BiometricUnlockController mBiometricUnlockController; private final NotificationPanelView mView; + private final VibratorHelper mVibratorHelper; private final MetricsLogger mMetricsLogger; private final ActivityManager mActivityManager; private final ConfigurationController mConfigurationController; @@ -518,12 +523,15 @@ public class NotificationPanelViewController extends PanelViewController { private final Rect mKeyguardStatusAreaClipBounds = new Rect(); private int mOldLayoutDirection; private NotificationShelfController mNotificationShelfController; + private int mScrimCornerRadius; + private int mScreenCornerRadius; + private int mNotificationScrimPadding; private final QuickAccessWalletClient mQuickAccessWalletClient; private final Executor mUiExecutor; private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL; - private int mScrimCornerRadius; + private KeyguardMediaController mKeyguardMediaController; private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() { @Override @@ -545,6 +553,14 @@ public class NotificationPanelViewController extends PanelViewController { } }; + private final FalsingTapListener mFalsingTapListener = new FalsingTapListener() { + @Override + public void onDoubleTapRequired() { + showTransientIndication(R.string.notification_tap_again); + mVibratorHelper.vibrate(VibrationEffect.EFFECT_STRENGTH_MEDIUM); + } + }; + @Inject public NotificationPanelViewController(NotificationPanelView view, @Main Resources resources, @@ -586,12 +602,15 @@ public class NotificationPanelViewController extends PanelViewController { LockIconViewController lockIconViewController, FeatureFlags featureFlags, QuickAccessWalletClient quickAccessWalletClient, + KeyguardMediaController keyguardMediaController, @Main Executor uiExecutor) { super(view, falsingManager, dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, vibratorHelper, statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(), statusBarTouchableRegionManager, ambientState); mView = view; + mVibratorHelper = vibratorHelper; + mKeyguardMediaController = keyguardMediaController; mMetricsLogger = metricsLogger; mActivityManager = activityManager; mConfigurationController = configurationController; @@ -759,7 +778,6 @@ public class NotificationPanelViewController extends PanelViewController { }); mView.setAccessibilityDelegate(mAccessibilityDelegate); - // dynamically apply the split shade value overrides. if (mShouldUseSplitNotificationShade) { updateResources(); } @@ -791,6 +809,12 @@ public class NotificationPanelViewController extends PanelViewController { com.android.internal.R.dimen.status_bar_height); mHeadsUpInset = statusbarHeight + mResources.getDimensionPixelSize( R.dimen.heads_up_status_bar_padding); + mScrimCornerRadius = mResources.getDimensionPixelSize( + R.dimen.notification_scrim_corner_radius); + mScreenCornerRadius = mResources.getDimensionPixelSize( + com.android.internal.R.dimen.rounded_corner_radius); + mNotificationScrimPadding = mResources.getDimensionPixelSize( + R.dimen.notification_side_paddings); } private void updateViewControllers(KeyguardStatusView keyguardStatusView, @@ -855,8 +879,6 @@ public class NotificationPanelViewController extends PanelViewController { public void updateResources() { mSplitShadeNotificationsTopPadding = mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade); - mScrimCornerRadius = - mResources.getDimensionPixelSize(R.dimen.notification_scrim_corner_radius); int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width); int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width); mShouldUseSplitNotificationShade = @@ -877,13 +899,17 @@ public class NotificationPanelViewController extends PanelViewController { constraintSet.connect( R.id.notification_stack_scroller, START, R.id.qs_edge_guideline, START); + constraintSet.connect(R.id.keyguard_status_view, END, R.id.qs_edge_guideline, END); } else { constraintSet.connect(R.id.qs_frame, END, PARENT_ID, END); constraintSet.connect(R.id.notification_stack_scroller, START, PARENT_ID, START); + constraintSet.connect(R.id.keyguard_status_view, END, PARENT_ID, END); } constraintSet.getConstraint(R.id.notification_stack_scroller).layout.mWidth = panelWidth; constraintSet.getConstraint(R.id.qs_frame).layout.mWidth = qsWidth; constraintSet.applyTo(mNotificationContainerParent); + + mKeyguardMediaController.refreshMediaPosition(); } private static void ensureAllViewsHaveIds(ViewGroup parentView) { @@ -917,12 +943,18 @@ public class NotificationPanelViewController extends PanelViewController { private void reInflateViews() { if (DEBUG) Log.d(TAG, "reInflateViews"); // Re-inflate the status view group. - KeyguardStatusView keyguardStatusView = mView.findViewById(R.id.keyguard_status_view); - int index = mView.indexOfChild(keyguardStatusView); - mView.removeView(keyguardStatusView); + KeyguardStatusView keyguardStatusView = + mNotificationContainerParent.findViewById(R.id.keyguard_status_view); + int statusIndex = mNotificationContainerParent.indexOfChild(keyguardStatusView); + mNotificationContainerParent.removeView(keyguardStatusView); keyguardStatusView = (KeyguardStatusView) mLayoutInflater.inflate( - R.layout.keyguard_status_view, mView, false); - mView.addView(keyguardStatusView, index); + R.layout.keyguard_status_view, mNotificationContainerParent, false); + mNotificationContainerParent.addView(keyguardStatusView, statusIndex); + attachSplitShadeMediaPlayerContainer( + keyguardStatusView.findViewById(R.id.status_view_media_container)); + + // we need to update KeyguardStatusView constraints after reinflating it + updateResources(); // Re-inflate the keyguard user switcher group. boolean isUserSwitcherEnabled = mUserManager.isUserSwitcherEnabled(); @@ -944,11 +976,11 @@ public class NotificationPanelViewController extends PanelViewController { showKeyguardUserSwitcher /* enabled */); mBigClockContainer.removeAllViews(); - updateViewControllers( - keyguardStatusView, userAvatarView, mKeyguardStatusBar, keyguardUserSwitcherView); + updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView, + mKeyguardStatusBar, keyguardUserSwitcherView); // Update keyguard bottom area - index = mView.indexOfChild(mKeyguardBottomArea); + int index = mView.indexOfChild(mKeyguardBottomArea); mView.removeView(mKeyguardBottomArea); KeyguardBottomAreaView oldBottomArea = mKeyguardBottomArea; mKeyguardBottomArea = (KeyguardBottomAreaView) mLayoutInflater.inflate( @@ -986,6 +1018,11 @@ public class NotificationPanelViewController extends PanelViewController { setKeyguardBottomAreaVisibility(mBarState, false); } + private void attachSplitShadeMediaPlayerContainer(FrameLayout container) { + mKeyguardMediaController.attachSplitShadeContainer(container, + () -> mShouldUseSplitNotificationShade); + } + private void initBottomArea() { mAffordanceHelper = new KeyguardAffordanceHelper( mKeyguardAffordanceHelperCallback, mView.getContext(), mFalsingManager); @@ -1098,7 +1135,8 @@ public class NotificationPanelViewController extends PanelViewController { hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount, bypassEnabled, getUnlockedStackScrollerPadding(), getQsExpansionFraction(), - mDisplayCutoutTopInset); + mDisplayCutoutTopInset, + shouldUseSplitNotificationShade(mFeatureFlags, mResources)); mClockPositionAlgorithm.run(mClockPositionResult); mKeyguardStatusViewController.updatePosition( mClockPositionResult.clockX, mClockPositionResult.clockY, @@ -1383,6 +1421,7 @@ public class NotificationPanelViewController extends PanelViewController { protected void flingToHeight(float vel, boolean expand, float target, float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) { mHeadsUpTouchHelper.notifyFling(!expand); + mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */); setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f); super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing); } @@ -2007,31 +2046,43 @@ public class NotificationPanelViewController extends PanelViewController { mMediaHierarchyManager.setQsExpansion(qsExpansionFraction); int qsPanelBottomY = calculateQsBottomPosition(qsExpansionFraction); mScrimController.setQsPosition(qsExpansionFraction, qsPanelBottomY); - setNotificationBounds(qsExpansionFraction, qsPanelBottomY); mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction); mDepthController.setQsPanelExpansion(qsExpansionFraction); } + private Runnable mOnStackYChanged = () -> { + if (mQs != null) { + setNotificationBounds(); + } + }; + /** * Updates scrim bounds, QS clipping, and KSV clipping as well based on the bounds of the shade * and QS state. - * - * @param qsFraction QS expansion fraction, from getQsExpansionFraction(). - * @param qsPanelBottomY Absolute y position of the bottom of QS as it's being pulled. */ - private void setNotificationBounds(float qsFraction, int qsPanelBottomY) { + private void setNotificationBounds() { int top = 0; int bottom = 0; int left = 0; int right = 0; - boolean visible = qsFraction > 0 || qsPanelBottomY > 0; + + final int qsPanelBottomY = calculateQsBottomPosition(getQsExpansionFraction()); + final boolean visible = (getQsExpansionFraction() > 0 || qsPanelBottomY > 0) + && !mShouldUseSplitNotificationShade; + final float notificationTop = mAmbientState.getStackY() + - mNotificationScrimPadding + - mAmbientState.getScrollY(); + setQsExpansionEnabled(mAmbientState.getScrollY() == 0); + + int radius = mScrimCornerRadius; if (visible || !mShouldUseSplitNotificationShade) { if (!mShouldUseSplitNotificationShade) { - float notificationTop = mAmbientState.getStackY() - mQsNotificationTopPadding; top = (int) Math.min(qsPanelBottomY, notificationTop); bottom = getView().getBottom(); left = getView().getLeft(); right = getView().getRight(); + radius = (int) MathUtils.lerp(mScreenCornerRadius, mScrimCornerRadius, + Math.min(top / (float) mScrimCornerRadius, 1f)); } else { top = Math.min(qsPanelBottomY, mSplitShadeNotificationsTopPadding); bottom = mNotificationStackScrollLayoutController.getHeight(); @@ -2040,17 +2091,18 @@ public class NotificationPanelViewController extends PanelViewController { } } + // Fancy clipping for quick settings + if (mQs != null) { + mQs.setFancyClipping(top, bottom, radius, visible); + } if (!mShouldUseSplitNotificationShade) { - // Fancy clipping for quick settings - if (mQs != null) { - mQs.setFancyClipping(top, bottom, mScrimCornerRadius, visible); - } // The padding on this area is large enough that we can use a cheaper clipping strategy mKeyguardStatusAreaClipBounds.set(left, top, right, bottom); mKeyguardStatusViewController.setClipBounds(visible ? mKeyguardStatusAreaClipBounds : null); } mScrimController.setNotificationsBounds(left, top, right, bottom); + mScrimController.setScrimCornerRadius(radius); } private int calculateQsBottomPosition(float qsExpansionFraction) { @@ -2204,6 +2256,7 @@ public class NotificationPanelViewController extends PanelViewController { break; case FLING_HIDE: default: + mQs.closeDetail(); target = 0; } if (target == mQsExpansionHeight) { @@ -3019,6 +3072,7 @@ public class NotificationPanelViewController extends PanelViewController { // The expandedHeight is always the full panel Height when bypassing expandedHeight = getMaxPanelHeightNonBypass(); } + mNotificationStackScrollLayoutController.setOnStackYChanged(mOnStackYChanged); mNotificationStackScrollLayoutController.setExpandedHeight(expandedHeight); updateKeyguardBottomAreaAlpha(); updateBigClockAlpha(); @@ -4015,6 +4069,7 @@ public class NotificationPanelViewController extends PanelViewController { // window, so // force a call to onThemeChanged mConfigurationListener.onThemeChanged(); + mFalsingManager.addTapListener(mFalsingTapListener); } @Override @@ -4023,6 +4078,7 @@ public class NotificationPanelViewController extends PanelViewController { mStatusBarStateController.removeCallback(mStatusBarStateListener); mConfigurationController.removeCallback(mConfigurationListener); mUpdateMonitor.removeCallback(mKeyguardUpdateCallback); + mFalsingManager.removeTapListener(mFalsingTapListener); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java index 0c8122cc9afb..388d72da808d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java @@ -256,7 +256,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW state.mScrimsVisibility == ScrimController.OPAQUE; final boolean keyguardOrAod = state.mKeyguardShowing || (state.mDozing && mDozeParameters.getAlwaysOn()); - if (keyguardOrAod && !state.mBackdropShowing && !scrimsOccludingWallpaper) { + if ((keyguardOrAod && !state.mBackdropShowing && !scrimsOccludingWallpaper) + || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) { + // Show the wallpaper if we're on keyguard/AOD and the wallpaper is not occluded by a + // solid backdrop or scrim. Also, show it if we are currently animating between the + // keyguard and the surface behind the keyguard - we want to use the wallpaper as a + // backdrop for this animation. mLpChanged.flags |= LayoutParams.FLAG_SHOW_WALLPAPER; } else { mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 5a2a6f21f94a..4714c4b5d476 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -592,6 +592,7 @@ public abstract class PanelViewController { float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) { if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) { InteractionJankMonitor.getInstance().end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); + mKeyguardStateController.notifyPanelFlingEnd(); notifyExpandingFinished(); return; } @@ -679,6 +680,7 @@ public abstract class PanelViewController { private void onFlingEnd(boolean cancelled) { setAnimator(null); + mKeyguardStateController.notifyPanelFlingEnd(); if (!cancelled) { InteractionJankMonitor.getInstance() .end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 0d96ead964f7..c09293115492 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -49,7 +49,6 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; import com.android.systemui.scrim.ScrimView; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.notification.stack.ViewState; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -211,10 +210,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump AlarmManager alarmManager, KeyguardStateController keyguardStateController, DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler, KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager, - ConfigurationController configurationController, - FeatureFlags featureFlags, @Main Executor mainExecutor) { + ConfigurationController configurationController, @Main Executor mainExecutor) { mScrimStateListener = lightBarController::setScrimState; - mDefaultScrimAlpha = featureFlags.isShadeOpaque() ? BUSY_SCRIM_ALPHA : GAR_SCRIM_ALPHA; + mDefaultScrimAlpha = BUSY_SCRIM_ALPHA; ScrimState.BUBBLE_EXPANDED.setBubbleAlpha(BUBBLE_SCRIM_ALPHA); mKeyguardStateController = keyguardStateController; @@ -269,7 +267,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump updateThemeColors(); behindScrim.enableBottomEdgeConcave(mClipsQsScrim); - mNotificationsScrim.enableRoundedCorners(); + mNotificationsScrim.enableRoundedCorners(true); if (mScrimBehindChangeRunnable != null) { mScrimBehind.setChangeRunnable(mScrimBehindChangeRunnable, mMainExecutor); @@ -294,6 +292,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mKeyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback); } + /** + * Sets corner radius of scrims. + */ + public void setScrimCornerRadius(int radius) { + if (mScrimBehind == null || mNotificationsScrim == null) { + return; + } + mScrimBehind.setCornerRadius(radius); + mNotificationsScrim.setCornerRadius(radius); + } + void setScrimVisibleListener(Consumer<Integer> listener) { mScrimVisibleListener = listener; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index 66cc26f5d295..1469cdab2d62 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -282,7 +282,7 @@ public enum ScrimState { public void prepare(ScrimState previousState) { mFrontTint = Color.TRANSPARENT; mBehindTint = Color.TRANSPARENT; - mBubbleTint = Color.TRANSPARENT; + mBubbleTint = Color.BLACK; mFrontAlpha = 0f; mBehindAlpha = mDefaultScrimAlpha; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 9d0285a5042f..137b7226f137 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -162,6 +162,7 @@ import com.android.systemui.emergency.EmergencyGesture; import com.android.systemui.fragments.ExtensionFragmentListener; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.keyguard.DismissCallbackRegistry; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; @@ -240,7 +241,6 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.tuner.TunerService; import com.android.systemui.volume.VolumeComponent; import com.android.systemui.wmshell.BubblesManager; import com.android.wm.shell.bubbles.Bubbles; @@ -799,8 +799,8 @@ public class StatusBar extends SystemUI implements DemoMode, OngoingCallController ongoingCallController, SystemStatusAnimationScheduler animationScheduler, PrivacyDotViewController dotViewController, - TunerService tunerService, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + KeyguardUnlockAnimationController keyguardUnlockAnimationController) { super(context); mNotificationsController = notificationsController; mLightBarController = lightBarController; @@ -884,15 +884,6 @@ public class StatusBar extends SystemUI implements DemoMode, mDotViewController = dotViewController; mFeatureFlags = featureFlags; - tunerService.addTunable( - (key, newValue) -> { - if (key.equals(Settings.Secure.DOZE_ALWAYS_ON)) { - updateLightRevealScrimVisibility(); - } - }, - Settings.Secure.DOZE_ALWAYS_ON - ); - mExpansionChangedListeners = new ArrayList<>(); mBubbleExpandListener = @@ -1036,6 +1027,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationShadeWindowViewController, mNotificationPanelViewController, mAmbientIndicationContainer); + mDozeParameters.addCallback(this::updateLightRevealScrimVisibility); mConfigurationController.addCallback(this); @@ -1122,6 +1114,8 @@ public class StatusBar extends SystemUI implements DemoMode, inflateShelf(); mNotificationIconAreaController.setupShelf(mNotificationShelfController); mNotificationPanelViewController.addExpansionListener(mWakeUpCoordinator); + mNotificationPanelViewController.addExpansionListener( + this::dispatchPanelExpansionForKeyguardDismiss); // Allow plugins to reference DarkIconDispatcher and StatusBarStateController mPluginDependencyProvider.allowPluginDependency(DarkIconDispatcher.class); @@ -1348,6 +1342,38 @@ public class StatusBar extends SystemUI implements DemoMode, ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f)); } + + /** + * When swiping up to dismiss the lock screen, the panel expansion goes from 1f to 0f. This + * results in the clock/notifications/other content disappearing off the top of the screen. + * + * We also use the expansion amount to animate in the app/launcher surface from the bottom of + * the screen, 'pushing' off the notifications and other content. To do this, we dispatch the + * expansion amount to the KeyguardViewMediator if we're in the process of dismissing the + * keyguard. + */ + private void dispatchPanelExpansionForKeyguardDismiss(float expansion, boolean trackingTouch) { + // Things that mean we're not dismissing the keyguard, and should ignore this expansion: + // - Keyguard isn't even visible. + // - Keyguard is visible, but can't be dismissed (swiping up will show PIN/password prompt). + // - QS is expanded and we're swiping - swiping up now will hide QS, not dismiss the + // keyguard. + if (!isKeyguardShowing() + || !mKeyguardStateController.canDismissLockScreen() + || (mNotificationPanelViewController.isQsExpanded() && trackingTouch)) { + return; + } + + // Otherwise, we should let the keyguard know about this if we're tracking touch, or if we + // are already animating the keyguard dismiss (since we will need to either finish or cancel + // the animation). + if (trackingTouch + || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) { + mKeyguardStateController.notifyKeyguardDismissAmountChanged( + 1f - expansion, trackingTouch); + } + } + @NonNull @Override public Lifecycle getLifecycle() { @@ -2015,9 +2041,12 @@ public class StatusBar extends SystemUI implements DemoMode, /** A launch animation was cancelled. */ //TODO: These can / should probably be moved to NotificationPresenter or ShadeController - public void onLaunchAnimationCancelled() { - if (!mPresenter.isCollapsing()) { + public void onLaunchAnimationCancelled(boolean isLaunchForActivity) { + if (mPresenter.isPresenterFullyCollapsed() && !mPresenter.isCollapsing() + && isLaunchForActivity) { onClosingFinished(); + } else { + mShadeController.collapsePanel(true /* animate */); } } @@ -2031,16 +2060,6 @@ public class StatusBar extends SystemUI implements DemoMode, } } - /** A launch animation timed out. */ - public void onLaunchAnimationTimedOut(boolean isLaunchForActivity) { - if (mPresenter.isPresenterFullyCollapsed() && !mPresenter.isCollapsing() - && isLaunchForActivity) { - onClosingFinished(); - } else { - mShadeController.collapsePanel(true /* animate */); - } - } - /** Whether we should animate an activity launch. */ public boolean areLaunchAnimationsEnabled() { // TODO(b/184121838): Support lock screen launch animations. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index ed63a227b041..f403cc94d831 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -572,6 +572,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } @Override + public void blockPanelExpansionFromCurrentTouch() { + mNotificationPanelViewController.blockExpansionForCurrentTouch(); + } + + @Override public void hide(long startTime, long fadeoutDuration) { mShowing = false; mKeyguardStateController.notifyKeyguardState(mShowing, @@ -584,7 +589,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb long uptimeMillis = SystemClock.uptimeMillis(); long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis); - if (mStatusBar.isInLaunchTransition() ) { + if (mStatusBar.isInLaunchTransition() + || mKeyguardStateController.isFlingingToDismissKeyguard()) { mStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() { @Override public void run() { @@ -609,7 +615,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb boolean needsFading = needsBypassFading(); if (needsFading) { delay = 0; - fadeoutDuration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION; + fadeoutDuration = KeyguardBypassController.BYPASS_FADE_DURATION; } else if (wakeUnlockPulsing) { delay = 0; fadeoutDuration = 240; @@ -973,7 +979,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb resetAlternateAuth(false); executeAfterKeyguardGoneAction(); } - } public void showBouncerMessage(String message, ColorStateList colorState) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt index 4a56020aebce..b2ab30785b4e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt @@ -43,16 +43,6 @@ class StatusBarLaunchAnimatorController( override fun onLaunchAnimationCancelled() { delegate.onLaunchAnimationCancelled() - statusBar.onLaunchAnimationCancelled() - } - - override fun onLaunchAnimationTimedOut() { - delegate.onLaunchAnimationTimedOut() - statusBar.onLaunchAnimationTimedOut(isLaunchForActivity) - } - - override fun onLaunchAnimationAborted() { - delegate.onLaunchAnimationAborted() - statusBar.collapsePanelOnMainThread() + statusBar.onLaunchAnimationCancelled(isLaunchForActivity) } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 088f9475c7d8..2b5caf91e024 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -364,7 +364,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, MetricsEvent.ACTION_LS_NOTE, 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */); mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_NOTIFICATION_FALSE_TOUCH); - mNotificationPanel.showTransientIndication(R.string.notification_tap_again); ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild(); if (previousView != null) { previousView.makeInactive(true /* animate */); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index 24e6db818ef6..66e1c2e1b571 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -38,6 +38,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.keyguard.DismissCallbackRegistry; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; @@ -102,7 +103,6 @@ import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.tuner.TunerService; import com.android.systemui.volume.VolumeComponent; import com.android.systemui.wmshell.BubblesManager; import com.android.wm.shell.bubbles.Bubbles; @@ -213,8 +213,8 @@ public interface StatusBarPhoneModule { OngoingCallController ongoingCallController, SystemStatusAnimationScheduler animationScheduler, PrivacyDotViewController dotViewController, - TunerService tunerService, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + KeyguardUnlockAnimationController keyguardUnlockAnimationController) { return new StatusBar( context, notificationsController, @@ -299,7 +299,7 @@ public interface StatusBarPhoneModule { ongoingCallController, animationScheduler, dotViewController, - tunerService, - featureFlags); + featureFlags, + keyguardUnlockAnimationController); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index 6ae5e904e4c7..95a7316f7a58 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -43,6 +43,13 @@ public interface BatteryController extends DemoMode, Dumpable, boolean isPluggedIn(); /** + * Returns {@code true} if the device is currently plugged in via wireless charger. + */ + default boolean isPluggedInWireless() { + return false; + } + + /** * Returns {@code true} if the device is currently in power save mode. */ boolean isPowerSave(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index 288eb3df3225..9e2c478fbd69 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -72,6 +72,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC protected int mLevel; protected boolean mPluggedIn; + private boolean mPluggedInWireless; protected boolean mCharging; private boolean mStateUnknown = false; private boolean mCharged; @@ -175,6 +176,8 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)); mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; + mPluggedInWireless = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) + == BatteryManager.BATTERY_PLUGGED_WIRELESS; final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN); @@ -260,6 +263,11 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC } @Override + public boolean isPluggedInWireless() { + return mPluggedInWireless; + } + + @Override public void getEstimatedTimeRemainingString(EstimateFetchCompletion completion) { // Need to fetch or refresh the estimate, but it may involve binder calls so offload the // work diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java index a0edc7c494bc..399c8500ab48 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java @@ -74,13 +74,11 @@ public class BrightnessMirrorController mBrightnessMirror.setVisibility(View.VISIBLE); mVisibilityCallback.accept(true); mNotificationPanel.setPanelAlpha(0, true /* animate */); - mDepthController.setBrightnessMirrorVisible(true); } public void hideMirror() { mVisibilityCallback.accept(false); mNotificationPanel.setPanelAlpha(255, true /* animate */); - mDepthController.setBrightnessMirrorVisible(false); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java index d52ea890af7e..9d667805fade 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java @@ -28,7 +28,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; -import com.android.internal.logging.UiEventLogger; import com.android.keyguard.KeyguardConstants; import com.android.keyguard.KeyguardVisibilityHelper; import com.android.keyguard.dagger.KeyguardUserSwitcherScope; @@ -36,7 +35,9 @@ import com.android.settingslib.drawable.CircleFramedDrawable; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.tiles.UserDetailView; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; @@ -48,6 +49,7 @@ import com.android.systemui.statusbar.phone.UserAvatarView; import com.android.systemui.util.ViewController; import javax.inject.Inject; +import javax.inject.Provider; /** * Manages the user switch on the Keyguard that is used for opening the QS user panel. @@ -67,7 +69,9 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie private final ScreenLifecycle mScreenLifecycle; private UserSwitcherController.BaseUserAdapter mAdapter; private final KeyguardStateController mKeyguardStateController; + private final FalsingManager mFalsingManager; protected final SysuiStatusBarStateController mStatusBarStateController; + private final ConfigurationController mConfigurationController; private final KeyguardVisibilityHelper mKeyguardVisibilityHelper; private final KeyguardUserDetailAdapter mUserDetailAdapter; private NotificationPanelViewController mNotificationPanelViewController; @@ -76,7 +80,6 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie // State info for the user switch and keyguard private int mBarState; - private float mDarkAmount; private final StatusBarStateController.StateListener mStatusBarStateListener = new StatusBarStateController.StateListener() { @@ -97,6 +100,15 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie } }; + private ConfigurationController.ConfigurationListener + mConfigurationListener = new ConfigurationController.ConfigurationListener() { + + @Override + public void onUiModeChanged() { + updateView(true); + } + }; + @Inject public KeyguardQsUserSwitchController( UserAvatarView view, @@ -106,9 +118,11 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie ScreenLifecycle screenLifecycle, UserSwitcherController userSwitcherController, KeyguardStateController keyguardStateController, + FalsingManager falsingManager, + ConfigurationController configurationController, SysuiStatusBarStateController statusBarStateController, DozeParameters dozeParameters, - UiEventLogger uiEventLogger) { + Provider<UserDetailView.Adapter> userDetailViewAdapterProvider) { super(view); if (DEBUG) Log.d(TAG, "New KeyguardQsUserSwitchController"); mContext = context; @@ -117,11 +131,12 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie mScreenLifecycle = screenLifecycle; mUserSwitcherController = userSwitcherController; mKeyguardStateController = keyguardStateController; + mFalsingManager = falsingManager; + mConfigurationController = configurationController; mStatusBarStateController = statusBarStateController; mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController, dozeParameters); - mUserDetailAdapter = new KeyguardUserDetailAdapter(mUserSwitcherController, mContext, - uiEventLogger); + mUserDetailAdapter = new KeyguardUserDetailAdapter(context, userDetailViewAdapterProvider); } @Override @@ -136,6 +151,10 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie }; mView.setOnClickListener(v -> { + if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { + return; + } + if (isListAnimating()) { return; } @@ -153,8 +172,6 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie R.string.accessibility_quick_settings_choose_user_action))); } }); - - updateView(true /* forceUpdate */); } @Override @@ -163,6 +180,8 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie mAdapter.registerDataSetObserver(mDataSetObserver); mDataSetObserver.onChanged(); mStatusBarStateController.addCallback(mStatusBarStateListener); + mConfigurationController.addCallback(mConfigurationListener); + updateView(true /* forceUpdate */); } @Override @@ -171,6 +190,7 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie mAdapter.unregisterDataSetObserver(mDataSetObserver); mStatusBarStateController.removeCallback(mStatusBarStateListener); + mConfigurationController.removeCallback(mConfigurationListener); } public final DataSetObserver mDataSetObserver = new DataSetObserver() { @@ -304,9 +324,9 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie } class KeyguardUserDetailAdapter extends UserSwitcherController.UserDetailAdapter { - KeyguardUserDetailAdapter(UserSwitcherController userSwitcherController, Context context, - UiEventLogger uiEventLogger) { - super(userSwitcherController, context, uiEventLogger); + KeyguardUserDetailAdapter(Context context, + Provider<UserDetailView.Adapter> userDetailViewAdapterProvider) { + super(context, userDetailViewAdapterProvider); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java index 692c34c62dd8..e7201f87b320 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java @@ -139,6 +139,38 @@ public interface KeyguardStateController extends CallbackController<Callback> { */ long calculateGoingToFullShadeDelay(); + /** + * How much (from 0f to 1f) the keyguard is dismissed, either via a swipe gesture or an + * animation. + */ + float getDismissAmount(); + + /** + * Whether the keyguard is being dismissed due to direct user input, rather than a canned + * animation. + */ + boolean isDismissingFromSwipe(); + + /** + * Whether a fling animation is currently playing on the keyguard, either to dismiss it or to + * cancel dismissing it. + */ + boolean isFlingingToDismissKeyguard(); + + /** + * Whether a fling animation is currently playing on the keyguard, either to dismiss it or to + * cancel dismissing it, and that animation started during a swipe gesture. Fling animations + * can also be started without a swipe (e.g. activity launch from lock screen notification), so + * this is a way to tell them apart for animation purposes. + */ + boolean isFlingingToDismissKeyguardDuringSwipeGesture(); + + /** + * Whether a fling animation is currently playing on the keyguard to cancel dismissing it, after + * the user released their finger during a swipe gesture. + */ + boolean isSnappingKeyguardBackAfterSwipe(); + /** **/ default void setLaunchTransitionFadingAway(boolean b) {} /** **/ @@ -149,6 +181,28 @@ public interface KeyguardStateController extends CallbackController<Callback> { default void notifyKeyguardState(boolean showing, boolean occluded) {} /** + * Updates the keyguard state to reflect that it's in the process of being dismissed, either by + * a swipe gesture on the lock screen or by a canned animation. + * + * @param dismissAmount 0f means we're not dismissed at all, 1f means we have been completely + * swiped away. + * @param dismissingFromTouch True if this change was caused by direct user interaction, false + * if it's due to an animation. + */ + default void notifyKeyguardDismissAmountChanged( + float dismissAmount, boolean dismissingFromTouch) {} + + /** + * Updates the keyguard state to reflect that a dismiss fling gesture has started. + * + * @param dismiss Whether we're flinging to dismiss (upward) or to cancel a dismiss gesture. + */ + void notifyPanelFlingStart(boolean dismiss); + + /** Updates the keyguard state to reflect that a dismiss fling gesture has ended. */ + void notifyPanelFlingEnd(); + + /** * Callback for authentication events. */ interface Callback { @@ -173,5 +227,11 @@ public interface KeyguardStateController extends CallbackController<Callback> { * Triggered when the device was just unlocked and the lock screen is being dismissed. */ default void onKeyguardFadingAwayChanged() {} + + /** + * Triggered when the keyguard dismiss amount has changed, via either a swipe gesture or an + * animation. + */ + default void onKeyguardDismissAmountChanged() {} } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java index 7f4eec745690..e69c1f2573b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java @@ -70,6 +70,28 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum private boolean mDebugUnlocked = false; private boolean mFaceAuthEnabled; + private float mDismissAmount = 0f; + private boolean mDismissingFromTouch = false; + + /** + * Whether the panel is currently flinging to a collapsed state, which means we're dismissing + * the keyguard. + */ + private boolean mFlingingToDismissKeyguard = false; + + /** + * Whether the panel is currently flinging to a collapsed state, which means we're dismissing + * the keyguard, and the fling started during a swipe gesture. This means that we need to take + * over the gesture and animate the rest of the way dismissed. + */ + private boolean mFlingingToDismissKeyguardDuringSwipeGesture = false; + + /** + * Whether the panel is currently flinging to an expanded state, which means we cancelled the + * dismiss gesture and are snapping back to the keyguard state. + */ + private boolean mSnappingKeyguardBackAfterSwipe = false; + /** */ @Inject @@ -241,11 +263,59 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum } @Override + public boolean isFlingingToDismissKeyguard() { + return mFlingingToDismissKeyguard; + } + + @Override + public boolean isFlingingToDismissKeyguardDuringSwipeGesture() { + return mFlingingToDismissKeyguardDuringSwipeGesture; + } + + @Override + public boolean isSnappingKeyguardBackAfterSwipe() { + return mSnappingKeyguardBackAfterSwipe; + } + + @Override + public float getDismissAmount() { + return mDismissAmount; + } + + @Override + public boolean isDismissingFromSwipe() { + return mDismissingFromTouch; + } + + @Override public void notifyKeyguardGoingAway(boolean keyguardGoingAway) { mKeyguardGoingAway = keyguardGoingAway; } @Override + public void notifyPanelFlingEnd() { + mFlingingToDismissKeyguard = false; + mFlingingToDismissKeyguardDuringSwipeGesture = false; + mSnappingKeyguardBackAfterSwipe = false; + } + + @Override + public void notifyPanelFlingStart(boolean flingToDismiss) { + mFlingingToDismissKeyguard = flingToDismiss; + mFlingingToDismissKeyguardDuringSwipeGesture = + flingToDismiss && mDismissingFromTouch; + mSnappingKeyguardBackAfterSwipe = !flingToDismiss; + } + + @Override + public void notifyKeyguardDismissAmountChanged(float dismissAmount, + boolean dismissingFromTouch) { + mDismissAmount = dismissAmount; + mDismissingFromTouch = dismissingFromTouch; + new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardDismissAmountChanged); + } + + @Override public void setLaunchTransitionFadingAway(boolean fadingAway) { mLaunchTransitionFadingAway = fadingAway; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 83558cbf089f..5c440173e547 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -78,6 +78,7 @@ import java.util.ArrayList; import java.util.List; import javax.inject.Inject; +import javax.inject.Provider; /** * Keeps a list of all users on the device for user switching. @@ -128,14 +129,14 @@ public class UserSwitcherController implements Dumpable { @Main Handler handler, ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger, TelephonyListenerManager telephonyListenerManager, - IActivityTaskManager activityTaskManager) { + IActivityTaskManager activityTaskManager, UserDetailAdapter userDetailAdapter) { mContext = context; mBroadcastDispatcher = broadcastDispatcher; mTelephonyListenerManager = telephonyListenerManager; mActivityTaskManager = activityTaskManager; mUiEventLogger = uiEventLogger; mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(mUiEventLogger); - mUserDetailAdapter = new UserDetailAdapter(this, mContext, mUiEventLogger); + mUserDetailAdapter = userDetailAdapter; if (!UserManager.isGuestUserEphemeral()) { mGuestResumeSessionReceiver.register(mBroadcastDispatcher); } @@ -577,11 +578,13 @@ public class UserSwitcherController implements Dumpable { pw.println("mSimpleUserSwitcher=" + mSimpleUserSwitcher); } - public String getCurrentUserName(Context context) { + /** Returns the name of the current user of the phone. */ + public String getCurrentUserName() { if (mUsers.isEmpty()) return null; UserRecord item = mUsers.get(0); if (item == null || item.info == null) return null; - if (item.isGuest) return context.getString(com.android.settingslib.R.string.guest_nickname); + if (item.isGuest) return mContext.getString( + com.android.settingslib.R.string.guest_nickname); return item.info.name; } @@ -787,15 +790,14 @@ public class UserSwitcherController implements Dumpable { public static class UserDetailAdapter implements DetailAdapter { private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS); - private final UserSwitcherController mUserSwitcherController; private final Context mContext; - private final UiEventLogger mUiEventLogger; + private final Provider<UserDetailView.Adapter> mUserDetailViewAdapterProvider; - UserDetailAdapter(UserSwitcherController userSwitcherController, Context context, - UiEventLogger uiEventLogger) { - mUserSwitcherController = userSwitcherController; + @Inject + UserDetailAdapter(Context context, + Provider<UserDetailView.Adapter> userDetailViewAdapterProvider) { mContext = context; - mUiEventLogger = uiEventLogger; + mUserDetailViewAdapterProvider = userDetailViewAdapterProvider; } @Override @@ -808,7 +810,7 @@ public class UserSwitcherController implements Dumpable { UserDetailView v; if (!(convertView instanceof UserDetailView)) { v = UserDetailView.inflate(context, parent, false); - v.createAndSetAdapter(mUserSwitcherController, mUiEventLogger); + v.setAdapter(mUserDetailViewAdapterProvider.get()); } else { v = (UserDetailView) convertView; } diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java index 570202845e86..755372b4b0f5 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java +++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java @@ -299,7 +299,7 @@ public class StorageNotification extends SystemUI { // but cause crash when call notifyAsUser(). Here we return directly for USER_NULL, and // leave all notifications belong to removed user to NotificationManagerService, the latter // will remove all notifications of the removed user when handles user stopped broadcast. - if (isAutomotive() && vol.getMountUserId() == UserHandle.USER_NULL) { + if (vol.getMountUserId() == UserHandle.USER_NULL) { Log.d(TAG, "Ignore public volume state change event of removed user"); return; } diff --git a/packages/SystemUI/src/com/android/systemui/util/DualHeightHorizontalLinearLayout.kt b/packages/SystemUI/src/com/android/systemui/util/DualHeightHorizontalLinearLayout.kt new file mode 100644 index 000000000000..0e04871106ef --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/DualHeightHorizontalLinearLayout.kt @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util + +import android.content.Context +import android.content.res.Configuration +import android.util.AttributeSet +import android.util.DisplayMetrics +import android.util.TypedValue +import android.widget.LinearLayout +import android.widget.TextView +import com.android.systemui.R + +/** + * Horizontal [LinearLayout] to contain some text. + * + * The height of this container can alternate between two different heights, depending on whether + * the text takes one line or more. + * + * When the text takes multiple lines, it will use the values in the regular attributes (`padding`, + * `layout_height`). The single line behavior must be set in XML. + * + * XML attributes for single line behavior: + * * `systemui:textViewId`: set the id for the [TextView] that determines the height of the + * container + * * `systemui:singleLineHeight`: sets the height of the view when the text takes up only one line. + * By default, it will use [getMinimumHeight]. + * * `systemui:singleLineVerticalPadding`: sets the padding (top and bottom) when then text takes up + * only one line. By default, it is 0. + * + * All dimensions are updated when configuration changes. + */ +class DualHeightHorizontalLinearLayout @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttrs: Int = 0, + defStyleRes: Int = 0 +) : LinearLayout(context, attrs, defStyleAttrs, defStyleRes) { + + private val singleLineHeightValue: TypedValue? + private var singleLineHeightPx = 0 + + private val singleLineVerticalPaddingValue: TypedValue? + private var singleLineVerticalPaddingPx = 0 + + private val textViewId: Int + private var textView: TextView? = null + + private val displayMetrics: DisplayMetrics + get() = context.resources.displayMetrics + + private var initialPadding = mPaddingTop // All vertical padding is the same + + init { + if (orientation != HORIZONTAL) { + throw IllegalStateException("This view should always have horizontal orientation") + } + + val ta = context.obtainStyledAttributes( + attrs, + R.styleable.DualHeightHorizontalLinearLayout, defStyleAttrs, defStyleRes + ) + + val tempHeight = TypedValue() + singleLineHeightValue = if ( + ta.hasValue(R.styleable.DualHeightHorizontalLinearLayout_singleLineHeight) + ) { + ta.getValue(R.styleable.DualHeightHorizontalLinearLayout_singleLineHeight, tempHeight) + tempHeight + } else { + null + } + + val tempPadding = TypedValue() + singleLineVerticalPaddingValue = if ( + ta.hasValue(R.styleable.DualHeightHorizontalLinearLayout_singleLineVerticalPadding) + ) { + ta.getValue( + R.styleable.DualHeightHorizontalLinearLayout_singleLineVerticalPadding, + tempPadding + ) + tempPadding + } else { + null + } + + textViewId = ta.getResourceId(R.styleable.DualHeightHorizontalLinearLayout_textViewId, 0) + + ta.recycle() + } + + init { + updateResources() + } + + override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) { + super.setPadding(left, top, right, bottom) + initialPadding = top + } + + override fun setPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) { + super.setPaddingRelative(start, top, end, bottom) + initialPadding = top + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + textView?.let { tv -> + if (tv.lineCount < 2) { + setMeasuredDimension(measuredWidth, singleLineHeightPx) + mPaddingBottom = 0 + mPaddingTop = 0 + } else { + mPaddingBottom = initialPadding + mPaddingTop = initialPadding + } + } + } + + override fun onFinishInflate() { + super.onFinishInflate() + textView = findViewById(textViewId) + } + + override fun onConfigurationChanged(newConfig: Configuration?) { + super.onConfigurationChanged(newConfig) + updateResources() + } + + override fun setOrientation(orientation: Int) { + if (orientation == VERTICAL) { + throw IllegalStateException("This view should always have horizontal orientation") + } + super.setOrientation(orientation) + } + + private fun updateResources() { + updateDimensionValue(singleLineHeightValue, minimumHeight, ::singleLineHeightPx::set) + updateDimensionValue(singleLineVerticalPaddingValue, 0, ::singleLineVerticalPaddingPx::set) + } + + private inline fun updateDimensionValue( + tv: TypedValue?, + defaultValue: Int, + propertySetter: (Int) -> Unit + ) { + val value = tv?.let { + if (it.resourceId != 0) { + context.resources.getDimensionPixelSize(it.resourceId) + } else { + it.getDimension(displayMetrics).toInt() + } + } ?: defaultValue + propertySetter(value) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java index 08cdebd5d80a..d2bbcd50d0e2 100644 --- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java @@ -34,6 +34,7 @@ import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.Debug; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -59,6 +60,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -489,12 +491,16 @@ public class GarbageMonitor implements Dumpable { ? "Dumping..." : mContext.getString(R.string.heap_dump_tile_name); if (pmi != null) { + final long views = Debug.countInstancesOfClass(View.class); + final long enrs = Debug.countInstancesOfClass(ExpandableNotificationRow.class); + Log.v(TAG, String.format("updating tile state; rss=%d", pmi.currentRss)); + Log.v(TAG, String.format("views: %d; ExpandableNotificationRows: %d", views, enrs)); icon.setRss(pmi.currentRss); state.secondaryLabel = String.format( - "rss: %s / %s", + "rss=%s views=%d\nenr=%d", formatBytes(pmi.currentRss * 1024), - formatBytes(gm.mHeapLimit * 1024)); + views, enrs); } else { icon.setRss(0); state.secondaryLabel = null; diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java index 141b9f7d410d..39a8bd94bf37 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java @@ -32,8 +32,9 @@ import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ChoreographerSfVsync; import com.android.wm.shell.common.annotations.ShellMainThread; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; +import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; +import com.android.wm.shell.startingsurface.tv.TvStartingWindowTypeAlgorithm; import com.android.wm.shell.transition.Transitions; import dagger.Module; @@ -80,4 +81,14 @@ public class TvWMShellModule { displayImeController, transactionPool, shellTaskOrganizer, syncQueue, taskStackListener, transitions, mainExecutor, sfVsyncAnimationHandler); } + + // + // Starting Windows (Splash Screen) + // + + @WMSingleton + @Provides + static StartingWindowTypeAlgorithm provideStartingWindowTypeAlgorithm() { + return new TvStartingWindowTypeAlgorithm(); + }; } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index f96d34495fda..26b68afed494 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -72,6 +72,7 @@ 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.startingsurface.StartingWindowTypeAlgorithm; import com.android.wm.shell.transition.ShellTransitions; import com.android.wm.shell.transition.Transitions; @@ -189,12 +190,13 @@ public abstract class WMShellBaseModule { TaskStackListenerImpl taskStackListener, UiEventLogger uiEventLogger, ShellTaskOrganizer organizer, + DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler) { return Optional.of(BubbleController.create(context, null /* synchronizer */, floatingContentCoordinator, statusBarService, windowManager, windowManagerShellWrapper, launcherApps, taskStackListener, - uiEventLogger, organizer, mainExecutor, mainHandler)); + uiEventLogger, organizer, displayController, mainExecutor, mainHandler)); } // @@ -381,8 +383,10 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static StartingWindowController provideStartingWindowController(Context context, - @ShellSplashscreenThread ShellExecutor splashScreenExecutor, TransactionPool pool) { - return new StartingWindowController(context, splashScreenExecutor, pool); + @ShellSplashscreenThread ShellExecutor splashScreenExecutor, + StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, TransactionPool pool) { + return new StartingWindowController(context, splashScreenExecutor, + startingWindowTypeAlgorithm, pool); } // diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index 743dd466d95e..36fd9bee80ab 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java @@ -54,6 +54,8 @@ import com.android.wm.shell.pip.phone.PipAppOpsListener; import com.android.wm.shell.pip.phone.PipController; import com.android.wm.shell.pip.phone.PipMotionHelper; import com.android.wm.shell.pip.phone.PipTouchHandler; +import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; +import com.android.wm.shell.startingsurface.phone.PhoneStartingWindowTypeAlgorithm; import com.android.wm.shell.transition.Transitions; import java.util.Optional; @@ -229,4 +231,14 @@ public class WMShellModule { menuController, pipSnapAlgorithm, pipTransitionController, floatingContentCoordinator); } + + // + // Starting Windows (Splash Screen) + // + + @WMSingleton + @Provides + static StartingWindowTypeAlgorithm provideStartingWindowTypeAlgorithm() { + return new PhoneStartingWindowTypeAlgorithm(); + } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java index 39ebe681841b..d07a8da47cf0 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java @@ -19,14 +19,21 @@ package com.android.keyguard; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.smartspace.SmartspaceTarget; import android.content.Context; +import android.content.pm.UserInfo; import android.content.res.Resources; +import android.os.Handler; +import android.os.UserHandle; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.util.AttributeSet; @@ -47,12 +54,15 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin.IntentStarter; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.NotificationIconContainer; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.util.settings.SecureSettings; import org.junit.Before; import org.junit.Test; @@ -62,6 +72,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.verification.VerificationMode; +import java.util.Collections; +import java.util.List; import java.util.concurrent.Executor; @SmallTest @@ -114,10 +126,23 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { ActivityStarter mActivityStarter; @Mock FalsingManager mFalsingManager; + @Mock + KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Mock + KeyguardBypassController mBypassController; + @Mock + Handler mHandler; + @Mock + UserTracker mUserTracker; + @Mock + SecureSettings mSecureSettings; private KeyguardClockSwitchController mController; private View mStatusArea; + private static final int USER_ID = 5; + private static final int MANAGED_USER_ID = 15; + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -152,7 +177,12 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { mConfigurationController, mSystemUIFactory, mActivityStarter, - mFalsingManager + mFalsingManager, + mKeyguardUpdateMonitor, + mBypassController, + mHandler, + mUserTracker, + mSecureSettings ); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); @@ -253,6 +283,89 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { verify(mSmartspaceView, times(2)).setPrimaryTextColor(anyInt()); } + @Test + public void doNotFilterRegularTarget() { + setupPrimaryAndManagedUser(); + mController.init(); + + when(mSecureSettings.getIntForUser(anyString(), anyInt(), eq(USER_ID))).thenReturn(0); + when(mSecureSettings.getIntForUser(anyString(), anyInt(), eq(MANAGED_USER_ID))) + .thenReturn(0); + + mController.getSettingsObserver().onChange(true, null); + + SmartspaceTarget t = mock(SmartspaceTarget.class); + when(t.isSensitive()).thenReturn(false); + when(t.getUserHandle()).thenReturn(new UserHandle(USER_ID)); + assertEquals(false, mController.filterSmartspaceTarget(t)); + + reset(t); + when(t.isSensitive()).thenReturn(false); + when(t.getUserHandle()).thenReturn(new UserHandle(MANAGED_USER_ID)); + assertEquals(false, mController.filterSmartspaceTarget(t)); + } + + @Test + public void filterAllSensitiveTargetsAllUsers() { + setupPrimaryAndManagedUser(); + mController.init(); + + when(mSecureSettings.getIntForUser(anyString(), anyInt(), eq(USER_ID))).thenReturn(0); + when(mSecureSettings.getIntForUser(anyString(), anyInt(), eq(MANAGED_USER_ID))) + .thenReturn(0); + + mController.getSettingsObserver().onChange(true, null); + + SmartspaceTarget t = mock(SmartspaceTarget.class); + when(t.isSensitive()).thenReturn(true); + when(t.getUserHandle()).thenReturn(new UserHandle(USER_ID)); + assertEquals(true, mController.filterSmartspaceTarget(t)); + + reset(t); + when(t.isSensitive()).thenReturn(true); + when(t.getUserHandle()).thenReturn(new UserHandle(MANAGED_USER_ID)); + assertEquals(true, mController.filterSmartspaceTarget(t)); + } + + @Test + public void filterSensitiveManagedUserTargets() { + setupPrimaryAndManagedUser(); + mController.init(); + + when(mSecureSettings.getIntForUser(anyString(), anyInt(), eq(USER_ID))).thenReturn(1); + when(mSecureSettings.getIntForUser(anyString(), anyInt(), eq(MANAGED_USER_ID))) + .thenReturn(0); + + mController.getSettingsObserver().onChange(true, null); + + SmartspaceTarget t = mock(SmartspaceTarget.class); + when(t.isSensitive()).thenReturn(true); + when(t.getUserHandle()).thenReturn(new UserHandle(USER_ID)); + assertEquals(false, mController.filterSmartspaceTarget(t)); + + reset(t); + when(t.isSensitive()).thenReturn(true); + when(t.getUserHandle()).thenReturn(new UserHandle(MANAGED_USER_ID)); + assertEquals(true, mController.filterSmartspaceTarget(t)); + } + + private void setupPrimaryAndManagedUser() { + UserInfo userInfo = mock(UserInfo.class); + when(userInfo.isManagedProfile()).thenReturn(true); + when(userInfo.getUserHandle()).thenReturn(new UserHandle(MANAGED_USER_ID)); + when(mUserTracker.getUserProfiles()).thenReturn(List.of(userInfo)); + + when(mUserTracker.getUserId()).thenReturn(USER_ID); + when(mUserTracker.getUserHandle()).thenReturn(new UserHandle(USER_ID)); + } + + private void setupPrimaryAndNoManagedUser() { + when(mUserTracker.getUserProfiles()).thenReturn(Collections.emptyList()); + + when(mUserTracker.getUserId()).thenReturn(USER_ID); + when(mUserTracker.getUserHandle()).thenReturn(new UserHandle(USER_ID)); + } + private void verifyAttachment(VerificationMode times) { verify(mClockManager, times).addOnClockChangedListener( any(ClockManager.ClockChangedListener.class)); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java index 4d526508ce0f..42314bf3643f 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java @@ -29,6 +29,7 @@ import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.testing.TestableResources; import android.view.Gravity; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -49,7 +50,6 @@ import org.mockito.junit.MockitoRule; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class KeyguardHostViewControllerTest extends SysuiTestCase { - @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @@ -68,14 +68,21 @@ public class KeyguardHostViewControllerTest extends SysuiTestCase { @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); + private TestableResources mTestableResources; private KeyguardHostViewController mKeyguardHostViewController; @Before public void setup() { - mContext.ensureTestableResources(); + mTestableResources = mContext.getOrCreateTestableResources(); mKeyguardHostView = new KeyguardHostView(mContext); + // Explicitly disable one handed keyguard. + mTestableResources.addOverride( + R.bool.can_use_one_handed_bouncer, false); + mTestableResources.addOverride( + com.android.internal.R.bool.config_enableOneHandedKeyguard, false); + when(mKeyguardSecurityContainerControllerFactory.create(any( KeyguardSecurityContainer.SecurityCallback.class))) .thenReturn(mKeyguardSecurityContainerController); @@ -106,7 +113,7 @@ public class KeyguardHostViewControllerTest extends SysuiTestCase { mKeyguardHostView.setLayoutParams(lp); // Set initial gravity - mContext.getOrCreateTestableResources().addOverride(R.integer.keyguard_host_view_gravity, + mTestableResources.addOverride(R.integer.keyguard_host_view_gravity, Gravity.CENTER); // Kick off the initial pass... @@ -116,9 +123,46 @@ public class KeyguardHostViewControllerTest extends SysuiTestCase { Gravity.CENTER); // Now simulate a config change - mContext.getOrCreateTestableResources().addOverride(R.integer.keyguard_host_view_gravity, + mTestableResources.addOverride(R.integer.keyguard_host_view_gravity, + Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); + + mKeyguardHostViewController.updateResources(); + assertEquals( + ((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity, + Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); + } + + @Test + public void testGravityUsesOneHandGravityWhenApplicable() { + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mKeyguardHostView.setLayoutParams(lp); + + mTestableResources.addOverride( + R.integer.keyguard_host_view_gravity, + Gravity.CENTER); + mTestableResources.addOverride( + R.integer.keyguard_host_view_one_handed_gravity, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); + // Start disabled. + mTestableResources.addOverride( + R.bool.can_use_one_handed_bouncer, false); + mTestableResources.addOverride( + com.android.internal.R.bool.config_enableOneHandedKeyguard, false); + + mKeyguardHostViewController.init(); + assertEquals( + ((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity, + Gravity.CENTER); + + // And enable + mTestableResources.addOverride( + R.bool.can_use_one_handed_bouncer, true); + mTestableResources.addOverride( + com.android.internal.R.bool.config_enableOneHandedKeyguard, true); + mKeyguardHostViewController.updateResources(); assertEquals( ((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity, diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java index 28cc580546be..0de257ad424b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java @@ -16,6 +16,9 @@ package com.android.systemui.accessibility.floatingmenu; +import static android.view.View.OVER_SCROLL_ALWAYS; +import static android.view.View.OVER_SCROLL_NEVER; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -437,6 +440,30 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase { action -> action.getId() == R.id.action_move_to_edge_and_hide)).isTrue(); } + @Test + public void onTargetsChanged_exceedAvailableHeight_overScrollAlways() { + final RecyclerView listView = new RecyclerView(mContext); + final AccessibilityFloatingMenuView menuView = + spy(new AccessibilityFloatingMenuView(mContext, listView)); + doReturn(true).when(menuView).hasExceededMaxLayoutHeight(); + + menuView.onTargetsChanged(mTargets); + + assertThat(listView.getOverScrollMode()).isEqualTo(OVER_SCROLL_ALWAYS); + } + + @Test + public void onTargetsChanged_notExceedAvailableHeight_overScrollNever() { + final RecyclerView listView = new RecyclerView(mContext); + final AccessibilityFloatingMenuView menuView = + spy(new AccessibilityFloatingMenuView(mContext, listView)); + doReturn(false).when(menuView).hasExceededMaxLayoutHeight(); + + mMenuView.onTargetsChanged(mTargets); + + assertThat(mListView.getOverScrollMode()).isEqualTo(OVER_SCROLL_NEVER); + } + @After public void tearDown() { mInterceptMotionEvent = null; diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt index 6420c4e2c481..c023610b6052 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt @@ -106,12 +106,12 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() { } @Test - fun abortsIfNoOpeningWindowIsFound() { + fun cancelsIfNoOpeningWindowIsFound() { val runner = activityLaunchAnimator.createRunner(controller) runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback) waitForIdleSync() - verify(controller).onLaunchAnimationAborted() + verify(controller).onLaunchAnimationCancelled() verify(controller, never()).onLaunchAnimationStart(anyBoolean()) } @@ -177,12 +177,4 @@ private class TestLaunchAnimatorController( override fun onLaunchAnimationCancelled() { assertOnMainThread() } - - override fun onLaunchAnimationTimedOut() { - assertOnMainThread() - } - - override fun onLaunchAnimationAborted() { - assertOnMainThread() - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 3fe8cee8d739..1b464a9b971b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -50,7 +50,9 @@ import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Bundle; +import android.os.RemoteException; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; @@ -66,6 +68,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.AdditionalMatchers; import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -100,12 +103,13 @@ public class AuthControllerTest extends SysuiTestCase { private FaceManager mFaceManager; @Mock private UdfpsController mUdfpsController; + @Captor + ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor; private TestableAuthController mAuthController; - @Before - public void setup() { + public void setup() throws RemoteException { MockitoAnnotations.initMocks(this); TestableContext context = spy(mContext); @@ -148,6 +152,9 @@ public class AuthControllerTest extends SysuiTestCase { () -> mUdfpsController); mAuthController.start(); + verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( + mAuthenticatorsRegisteredCaptor.capture()); + mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props); } // Callback tests 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 725f0e6a3b94..40c48514f159 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -24,7 +24,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.res.Resources; import android.content.res.TypedArray; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; @@ -40,6 +39,7 @@ import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; @@ -85,8 +85,6 @@ public class UdfpsControllerTest extends SysuiTestCase { // Dependencies @Mock - private Resources mResources; - @Mock private LayoutInflater mLayoutInflater; @Mock private FingerprintManager mFingerprintManager; @@ -110,6 +108,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private FalsingManager mFalsingManager; @Mock private PowerManager mPowerManager; + @Mock + private AccessibilityManager mAccessibilityManager; private FakeExecutor mFgExecutor; @@ -151,7 +151,6 @@ public class UdfpsControllerTest extends SysuiTestCase { mFgExecutor = new FakeExecutor(new FakeSystemClock()); mUdfpsController = new UdfpsController( mContext, - mResources, mLayoutInflater, mFingerprintManager, mWindowManager, @@ -163,7 +162,8 @@ public class UdfpsControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor, mKeyguardViewMediator, mFalsingManager, - mPowerManager); + mPowerManager, + mAccessibilityManager); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); @@ -174,16 +174,9 @@ public class UdfpsControllerTest extends SysuiTestCase { when(mBrightnessValues.length()).thenReturn(2); when(mBrightnessValues.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f); when(mBrightnessValues.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f); - when(mResources.obtainTypedArray(com.android.internal.R.array.config_screenBrightnessNits)) - .thenReturn(mBrightnessValues); when(mBrightnessBacklight.length()).thenReturn(2); when(mBrightnessBacklight.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f); when(mBrightnessBacklight.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f); - when(mResources.obtainTypedArray( - com.android.internal.R.array.config_autoBrightnessDisplayValuesNits)) - .thenReturn(mBrightnessBacklight); - when(mResources.getIntArray(com.android.internal.R.array.config_screenBrightnessBacklight)) - .thenReturn(new int[]{1, 2}); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java index fe2103ccc557..724f8a3adf80 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java @@ -42,6 +42,7 @@ public class DozeConfigurationUtil { when(params.getSelectivelyRegisterSensorsUsingProx()).thenReturn(false); when(params.singleTapUsesProx()).thenReturn(true); when(params.longPressUsesProx()).thenReturn(true); + when(params.getQuickPickupAodDuration()).thenReturn(500); doneHolder[0] = true; return params; diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index 8eb0e9c5d0ab..4a9d66c16003 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -35,10 +35,12 @@ import android.view.Display; import androidx.test.filters.SmallTest; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dock.DockManager; +import com.android.systemui.doze.DozeTriggers.DozingUpdateUiEvent; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.FakeThreadFactory; @@ -76,6 +78,8 @@ public class DozeTriggersTest extends SysuiTestCase { private ProximitySensor.ProximityCheck mProximityCheck; @Mock private AuthController mAuthController; + @Mock + private UiEventLogger mUiEventLogger; private DozeTriggers mTriggers; private FakeSensorManager mSensors; @@ -107,7 +111,7 @@ public class DozeTriggersTest extends SysuiTestCase { mTriggers = new DozeTriggers(mContext, mHost, config, dozeParameters, asyncSensorManager, wakeLock, mDockManager, mProximitySensor, mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher, new FakeSettings(), - mAuthController, mExecutor); + mAuthController, mExecutor, mUiEventLogger); mTriggers.setDozeMachine(mMachine); waitForSensorManager(); } @@ -195,6 +199,40 @@ public class DozeTriggersTest extends SysuiTestCase { } @Test + public void testQuickPickup() { + // GIVEN device is in doze (screen blank, but running doze sensors) + when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE); + + // WHEN quick pick up is triggered + mTriggers.onSensor(DozeLog.REASON_SENSOR_QUICK_PICKUP, 100, 100, null); + + // THEN device goes into aod (shows clock with black background) + verify(mMachine).requestState(DozeMachine.State.DOZE_AOD); + + // THEN a log is taken that quick pick up was triggered + verify(mUiEventLogger).log(DozingUpdateUiEvent.DOZING_UPDATE_QUICK_PICKUP); + } + + @Test + public void testQuickPickupTimeOutAfterExecutables() { + // GIVEN quick pickup is triggered when device is in DOZE + when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE); + mTriggers.onSensor(DozeLog.REASON_SENSOR_QUICK_PICKUP, 100, 100, null); + verify(mMachine).requestState(DozeMachine.State.DOZE_AOD); + verify(mMachine, never()).requestState(DozeMachine.State.DOZE); + + // WHEN next executable is run + mExecutor.advanceClockToLast(); + mExecutor.runAllReady(); + + // THEN device goes back into DOZE + verify(mMachine).requestState(DozeMachine.State.DOZE); + + // THEN a log is taken that wake up timeout expired + verify(mUiEventLogger).log(DozingUpdateUiEvent.DOZING_UPDATE_WAKE_TIMEOUT); + } + + @Test public void testOnSensor_Fingerprint() { final int screenX = 100; final int screenY = 100; diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index b8c37fde2ce3..5c87741b8883 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -29,17 +29,13 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.app.ActivityManager; -import android.app.ActivityTaskManager; import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; -import android.view.View; -import com.android.systemui.R; import androidx.test.filters.SmallTest; import com.android.internal.widget.LockPatternUtils; @@ -51,9 +47,9 @@ import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.LightRevealScrim; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; @@ -84,6 +80,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock KeyguardDisplayManager mKeyguardDisplayManager; private @Mock DozeParameters mDozeParameters; private @Mock StatusBarStateController mStatusBarStateController; + private @Mock KeyguardStateController mKeyguardStateController; + private @Mock KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); @@ -102,7 +100,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { () -> mStatusBarKeyguardViewManager, mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor, mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController, - mKeyguardDisplayManager, mDozeParameters, mStatusBarStateController); + mKeyguardDisplayManager, mDozeParameters, mStatusBarStateController, + mKeyguardStateController, () -> mKeyguardUnlockAnimationController); mViewMediator.start(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt index 730c941cc414..0d67d664c078 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt @@ -19,26 +19,23 @@ package com.android.systemui.media import android.testing.AndroidTestingRunner import android.view.View.GONE import android.view.View.VISIBLE +import android.widget.FrameLayout import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.stack.MediaHeaderView import com.android.systemui.statusbar.phone.KeyguardBypassController -import com.android.systemui.util.mockito.capture +import com.android.systemui.util.animation.UniqueObjectHostView +import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor -import org.mockito.Captor import org.mockito.Mock -import org.mockito.Mockito.`when` -import org.mockito.Mockito.atLeastOnce -import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit +import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidTestingRunner::class) @@ -52,51 +49,81 @@ class KeyguardMediaControllerTest : SysuiTestCase() { private lateinit var statusBarStateController: SysuiStatusBarStateController @Mock private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager - @Mock - private lateinit var mediaHeaderView: MediaHeaderView - @Captor - private lateinit var visibilityListener: ArgumentCaptor<((Boolean) -> Unit)> @JvmField @Rule val mockito = MockitoJUnit.rule() + + private val mediaHeaderView: MediaHeaderView = MediaHeaderView(context, null) private lateinit var keyguardMediaController: KeyguardMediaController @Before fun setup() { + // default state is positive, media should show up + whenever(mediaHost.visible).thenReturn(true) + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications()) + .thenReturn(true) + whenever(mediaHost.hostView).thenReturn(UniqueObjectHostView(context)) + keyguardMediaController = KeyguardMediaController(mediaHost, bypassController, statusBarStateController, notificationLockscreenUserManager) + keyguardMediaController.attachSinglePaneContainer(mediaHeaderView) } @Test - fun testAttach_hiddenWhenHostIsHidden() { - `when`(mediaHost.visible).thenReturn(false) - triggerVisibilityListener() + fun testHiddenWhenHostIsHidden() { + whenever(mediaHost.visible).thenReturn(false) + + keyguardMediaController.refreshMediaPosition() - verify(mediaHeaderView, atLeastOnce()).visibility = eq(GONE) + assertThat(mediaHeaderView.visibility).isEqualTo(GONE) } + @Test - fun testAttach_visibleOnKeyguard() { - `when`(mediaHost.visible).thenReturn(true) - `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) - `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()) - .thenReturn(true) - triggerVisibilityListener() + fun testVisibleOnKeyguardOrFullScreenUserSwitcher() { + testStateVisibility(StatusBarState.SHADE, GONE) + testStateVisibility(StatusBarState.SHADE_LOCKED, GONE) + testStateVisibility(StatusBarState.FULLSCREEN_USER_SWITCHER, VISIBLE) + testStateVisibility(StatusBarState.KEYGUARD, VISIBLE) + } - verify(mediaHeaderView, atLeastOnce()).visibility = eq(VISIBLE) + private fun testStateVisibility(state: Int, visibility: Int) { + whenever(statusBarStateController.state).thenReturn(state) + keyguardMediaController.refreshMediaPosition() + assertThat(mediaHeaderView.visibility).isEqualTo(visibility) } + @Test - fun testAttach_hiddenOnKeyguard_whenNotificationsAreHidden() { - `when`(mediaHost.visible).thenReturn(true) - `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) - `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()) + fun testHiddenOnKeyguard_whenNotificationsAreHidden() { + whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications()) .thenReturn(false) - triggerVisibilityListener() - verify(mediaHeaderView, atLeastOnce()).visibility = eq(GONE) + keyguardMediaController.refreshMediaPosition() + + assertThat(mediaHeaderView.visibility).isEqualTo(GONE) } - private fun triggerVisibilityListener() { - keyguardMediaController.attach(mediaHeaderView) - verify(mediaHost).addVisibilityChangeListener(capture(visibilityListener)) - visibilityListener.value.invoke(true) + @Test + fun testActivatesSplitShadeContainerInSplitShadeMode() { + val splitShadeContainer = FrameLayout(context) + keyguardMediaController.attachSplitShadeContainer( + splitShadeContainer, + useContainer = { true }) + + keyguardMediaController.refreshMediaPosition() + + assertThat(splitShadeContainer.visibility).isEqualTo(VISIBLE) + } + + @Test + fun testActivatesSinglePaneContainerInSinglePaneMode() { + val splitShadeContainer = FrameLayout(context) + keyguardMediaController.attachSplitShadeContainer( + splitShadeContainer, + useContainer = { false }) + + keyguardMediaController.refreshMediaPosition() + + assertThat(splitShadeContainer.visibility).isEqualTo(GONE) + assertThat(mediaHeaderView.visibility).isEqualTo(VISIBLE) } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index 73b0a6b9a11a..94252d2b8331 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -95,7 +95,6 @@ public class MediaControlPanelTest : SysuiTestCase() { @Mock private lateinit var collapsedSet: ConstraintSet @Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory private lateinit var appIcon: ImageView - private lateinit var appName: TextView private lateinit var albumView: ImageView private lateinit var titleText: TextView private lateinit var artistText: TextView @@ -138,8 +137,6 @@ public class MediaControlPanelTest : SysuiTestCase() { whenever(holder.player).thenReturn(view) appIcon = ImageView(context) whenever(holder.appIcon).thenReturn(appIcon) - appName = TextView(context) - whenever(holder.appName).thenReturn(appName) albumView = ImageView(context) whenever(holder.albumView).thenReturn(albumView) titleText = TextView(context) @@ -220,7 +217,6 @@ public class MediaControlPanelTest : SysuiTestCase() { val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null) player.bindPlayer(state, PACKAGE) - assertThat(appName.getText()).isEqualTo(APP) assertThat(titleText.getText()).isEqualTo(TITLE) assertThat(artistText.getText()).isEqualTo(ARTIST) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt index a9d256bf37cc..ac24cdeb74bc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.media +import android.app.smartspace.SmartspaceAction import android.app.smartspace.SmartspaceTarget import android.graphics.Color import androidx.test.filters.SmallTest @@ -72,6 +73,8 @@ class MediaDataFilterTest : SysuiTestCase() { private lateinit var executor: Executor @Mock private lateinit var smartspaceData: SmartspaceTarget + @Mock + private lateinit var smartspaceMediaRecommendationItem: SmartspaceAction private lateinit var mediaDataFilter: MediaDataFilter private lateinit var dataMain: MediaData @@ -97,6 +100,7 @@ class MediaDataFilterTest : SysuiTestCase() { emptyList(), emptyList(), PACKAGE, null, null, device, true, null) `when`(smartspaceData.smartspaceTargetId).thenReturn(SMARTSPACE_KEY) + `when`(smartspaceData.iconGrid).thenReturn(listOf(smartspaceMediaRecommendationItem)) } private fun setUser(id: Int) { @@ -222,7 +226,7 @@ class MediaDataFilterTest : SysuiTestCase() { } @Test - fun testOnSmartspaceMediaDataLoaded_noMedia_usesSmartspace() { + fun testOnSmartspaceMediaDataLoaded_noMedia_nonEmptyRecommendation_usesSmartspace() { mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData)) @@ -230,7 +234,18 @@ class MediaDataFilterTest : SysuiTestCase() { } @Test - fun testOnSmartspaceMediaDataLoaded_noRecentMedia_usesSmartspace() { + fun testOnSmartspaceMediaDataLoaded_noMedia_emptyRecommendation_showsNothing() { + `when`(smartspaceData.iconGrid).thenReturn(listOf()) + + mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) + + verify(listener, never()) + .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData)) + assertThat(mediaDataFilter.hasActiveMedia()).isTrue() + } + + @Test + fun testOnSmartspaceMediaDataLoaded_noRecentMedia_nonEmptyRecommendation_usesSmartspace() { val dataOld = dataMain.copy(active = false, lastActive = 0L) mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) @@ -240,6 +255,19 @@ class MediaDataFilterTest : SysuiTestCase() { } @Test + fun testOnSmartspaceMediaDataLoaded_noRecentMedia_emptyRecommendation_showsNothing() { + `when`(smartspaceData.iconGrid).thenReturn(listOf()) + + val dataOld = dataMain.copy(active = false, lastActive = 0L) + mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld) + mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) + + verify(listener, never()) + .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData)) + assertThat(mediaDataFilter.hasActiveMedia()).isTrue() + } + + @Test fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_usesMedia() { // WHEN we have media that was recently played, but not currently active val dataCurrent = dataMain.copy(active = false, lastActive = System.currentTimeMillis()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt index 678f89a06479..daa8b4bbb6d0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -425,4 +425,30 @@ class MediaDataManagerTest : SysuiTestCase() { assertThat(mediaDataCaptor.value.resumption).isTrue() assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTimeMillis) } + + @Test + fun testTooManyCompactActions_isTruncated() { + // GIVEN a notification where too many compact actions were specified + val notif = SbnBuilder().run { + setPkg(PACKAGE_NAME) + modifyNotification(context).also { + it.setSmallIcon(android.R.drawable.ic_media_pause) + it.setStyle(MediaStyle().apply { + setMediaSession(session.sessionToken) + setShowActionsInCompactView(0, 1, 2, 3, 4) + }) + } + build() + } + + // WHEN the notification is loaded + mediaDataManager.onNotificationAdded(KEY, notif) + assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) + assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) + + // THEN only the first MAX_COMPACT_ACTIONS are actually set + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor)) + assertThat(mediaDataCaptor.value.actionsToShowInCompact.size).isEqualTo( + MediaDataManager.MAX_COMPACT_ACTIONS) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java index 37b7cbeb8ad6..0eeb955e6b42 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java @@ -36,6 +36,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestableContext; import com.android.systemui.assist.AssistManager; import com.android.systemui.navigationbar.NavigationBarView; +import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -67,6 +68,7 @@ public class NavigationBarButtonTest extends SysuiTestCase { mDependency.injectMockDependency(OverviewProxyService.class); mDependency.injectMockDependency(KeyguardStateController.class); mDependency.injectMockDependency(NavigationBarController.class); + mDependency.injectMockDependency(EdgeBackGestureHandler.class); mNavBar = new NavigationBarView(context, null); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java index f0c48bd198ff..4ec45b444c46 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java @@ -72,6 +72,7 @@ import com.android.systemui.accessibility.SystemActions; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.model.SysUiState; +import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; @@ -132,6 +133,7 @@ public class NavigationBarTest extends SysuiTestCase { mDependency.injectMockDependency(StatusBarStateController.class); mDependency.injectMockDependency(NavigationBarController.class); mOverviewProxyService = mDependency.injectMockDependency(OverviewProxyService.class); + mDependency.injectMockDependency(EdgeBackGestureHandler.class); TestableLooper.get(this).runWithLooper(() -> { mNavigationBar = createNavBar(mContext); mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal); diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java index 7e0920cc998d..e4d32f4db709 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java @@ -32,9 +32,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; -import com.android.systemui.navigationbar.NavigationBarTransitions; -import com.android.systemui.navigationbar.NavigationBarView; -import com.android.systemui.navigationbar.NavigationModeController; +import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.statusbar.CommandQueue; @@ -60,6 +58,7 @@ public class NavigationBarTransitionsTest extends SysuiTestCase { mDependency.injectMockDependency(StatusBarStateController.class); mDependency.injectMockDependency(KeyguardStateController.class); mDependency.injectMockDependency(NavigationBarController.class); + mDependency.injectMockDependency(EdgeBackGestureHandler.class); doReturn(mContext) .when(mDependency.injectMockDependency(NavigationModeController.class)) .getCurrentUserContext(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java index 7cddc3f8e82d..1b713dd8de88 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java @@ -19,6 +19,7 @@ import static android.app.Notification.CATEGORY_MISSED_CALL; import static com.android.systemui.people.NotificationHelper.getHighestPriorityNotification; import static com.android.systemui.people.NotificationHelper.getMessagingStyleMessages; +import static com.android.systemui.people.NotificationHelper.getSenderIfGroupConversation; import static com.android.systemui.people.NotificationHelper.isMissedCall; import static com.android.systemui.people.NotificationHelper.isMissedCallOrHasContent; import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME; @@ -32,6 +33,7 @@ import android.app.Notification; import android.app.Person; import android.content.pm.ShortcutInfo; import android.net.Uri; +import android.os.Bundle; import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; @@ -202,4 +204,53 @@ public class NotificationHelperTest extends SysuiTestCase { assertThat(getHighestPriorityNotification(notifications)) .isEqualTo(mNotificationEntry1); } + + @Test + public void testGetSenderIfGroupConversation_notGroup() { + Notification.MessagingStyle.Message message = new Notification.MessagingStyle.Message( + NOTIFICATION_TEXT_3, 10, PERSON); + Notification notification = new Notification.Builder(mContext, "test") + .setContentTitle("TEST_TITLE") + .setContentText("TEST_TEXT") + .setShortcutId(SHORTCUT_ID_1) + .setStyle(new Notification.MessagingStyle(PERSON).addMessage(message)) + .build(); + assertThat(getSenderIfGroupConversation(notification, message)).isNull(); + } + + @Test + public void testGetSenderIfGroupConversation_group() { + Bundle extras = new Bundle(); + extras.putBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION, true); + Notification.MessagingStyle.Message message = new Notification.MessagingStyle.Message( + NOTIFICATION_TEXT_3, 10, PERSON); + + Notification notification = new Notification.Builder(mContext, "test") + .setContentTitle("TEST_TITLE") + .setContentText("TEST_TEXT") + .setShortcutId(SHORTCUT_ID_1) + .setStyle(new Notification.MessagingStyle(PERSON) + .setGroupConversation(true) + .addMessage(message)) + .addExtras(extras) + .build(); + assertThat(getSenderIfGroupConversation(notification, message)).isEqualTo("name"); + } + + @Test + public void testGetSenderIfGroupConversation_groupNoName() { + Bundle extras = new Bundle(); + extras.putBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION, true); + Notification.MessagingStyle.Message message = new Notification.MessagingStyle.Message( + NOTIFICATION_TEXT_3, 10, new Person.Builder().build()); + + Notification notification = new Notification.Builder(mContext, "test") + .setContentTitle("TEST_TITLE") + .setContentText("TEST_TEXT") + .setShortcutId(SHORTCUT_ID_1) + .setStyle(new Notification.MessagingStyle(PERSON).addMessage(message)) + .setExtras(extras) + .build(); + assertThat(getSenderIfGroupConversation(notification, message)).isNull(); + } } 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 c929073d9a09..cc322620eb57 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java @@ -59,6 +59,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.appwidget.IAppWidgetService; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.people.widget.PeopleTileKey; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -94,6 +95,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { private static final Uri URI = Uri.parse("fake_uri"); private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android); private static final String NAME = "username"; + private static final UserHandle USER = new UserHandle(0); private static final Person PERSON = new Person.Builder() .setName("name") .setKey("abc") @@ -103,6 +105,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { private static final PeopleSpaceTile PERSON_TILE = new PeopleSpaceTile .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent()) + .setUserHandle(USER) .setLastInteractionTimestamp(123L) .setNotificationKey(NOTIFICATION_KEY) .setNotificationContent(NOTIFICATION_CONTENT) @@ -231,10 +234,51 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { .setPackageName(PACKAGE_NAME) .setUserHandle(new UserHandle(0)) .build(); + PeopleTileKey key = new PeopleTileKey(tile); PeopleSpaceTile actual = PeopleSpaceUtils - .augmentTileFromNotification(mContext, tile, mNotificationEntry1, 0); + .augmentTileFromNotification(mContext, tile, key, mNotificationEntry1, 0); assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_2); + assertThat(actual.getNotificationSender()).isEqualTo(null); + } + + @Test + public void testAugmentTileFromNotificationGroupWithSender() { + Bundle extras = new Bundle(); + extras.putBoolean(Notification.EXTRA_IS_GROUP_CONVERSATION, true); + Notification notification = new Notification.Builder(mContext, "test") + .setContentTitle("TEST_TITLE") + .setContentText("TEST_TEXT") + .setShortcutId(SHORTCUT_ID_1) + .setStyle(new Notification.MessagingStyle(PERSON) + .setGroupConversation(true) + .addMessage(new Notification.MessagingStyle.Message( + NOTIFICATION_TEXT_1, 0, PERSON)) + .addMessage(new Notification.MessagingStyle.Message( + NOTIFICATION_TEXT_2, 20, PERSON)) + .addMessage(new Notification.MessagingStyle.Message( + NOTIFICATION_TEXT_3, 10, PERSON)) + ) + .setExtras(extras) + .build(); + NotificationEntry notificationEntry = new NotificationEntryBuilder() + .setNotification(notification) + .setShortcutInfo(new ShortcutInfo.Builder(mContext, SHORTCUT_ID_1).build()) + .setUser(UserHandle.of(0)) + .setPkg(PACKAGE_NAME) + .build(); + PeopleSpaceTile tile = + new PeopleSpaceTile + .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent()) + .setPackageName(PACKAGE_NAME) + .setUserHandle(new UserHandle(0)) + .build(); + PeopleTileKey key = new PeopleTileKey(tile); + PeopleSpaceTile actual = PeopleSpaceUtils + .augmentTileFromNotification(mContext, tile, key, notificationEntry, 0); + + assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_2); + assertThat(actual.getNotificationSender().toString()).isEqualTo("name"); } @Test @@ -245,8 +289,9 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { .setPackageName(PACKAGE_NAME) .setUserHandle(new UserHandle(0)) .build(); + PeopleTileKey key = new PeopleTileKey(tile); PeopleSpaceTile actual = PeopleSpaceUtils - .augmentTileFromNotification(mContext, tile, mNotificationEntry3, 0); + .augmentTileFromNotification(mContext, tile, key, mNotificationEntry3, 0); assertThat(actual.getNotificationContent()).isEqualTo(null); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java index 3cc55f2f9070..d353d529865b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java @@ -42,6 +42,7 @@ import android.content.res.Resources; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Bundle; +import android.os.UserHandle; import android.testing.AndroidTestingRunner; import android.util.DisplayMetrics; import android.view.View; @@ -73,10 +74,13 @@ public class PeopleTileViewHelperTest extends SysuiTestCase { private static final String GAME_DESCRIPTION = "Playing a game!"; private static final CharSequence MISSED_CALL = "Custom missed call message"; private static final String NAME = "username"; + private static final UserHandle USER = new UserHandle(0); + private static final String SENDER = "sender"; private static final PeopleSpaceTile PERSON_TILE_WITHOUT_NOTIFICATION = new PeopleSpaceTile .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent()) .setLastInteractionTimestamp(0L) + .setUserHandle(USER) .build(); private static final PeopleSpaceTile PERSON_TILE = new PeopleSpaceTile @@ -85,6 +89,16 @@ public class PeopleTileViewHelperTest extends SysuiTestCase { .setNotificationKey(NOTIFICATION_KEY) .setNotificationContent(NOTIFICATION_CONTENT) .setNotificationDataUri(URI) + .setUserHandle(USER) + .build(); + private static final PeopleSpaceTile PERSON_TILE_WITH_SENDER = + new PeopleSpaceTile + .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent()) + .setLastInteractionTimestamp(123L) + .setNotificationKey(NOTIFICATION_KEY) + .setNotificationContent(NOTIFICATION_CONTENT) + .setNotificationSender(SENDER) + .setUserHandle(USER) .build(); private static final ConversationStatus GAME_STATUS = new ConversationStatus @@ -534,6 +548,86 @@ public class PeopleTileViewHelperTest extends SysuiTestCase { } @Test + public void testCreateRemoteViewsWithNotificationWithSenderTemplate() { + PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE_WITH_SENDER.toBuilder() + .setNotificationDataUri(null) + .setStatuses(Arrays.asList(GAME_STATUS, + NEW_STORY_WITH_AVAILABILITY)).build(); + RemoteViews views = new PeopleTileViewHelper(mContext, + tileWithStatusAndNotification, 0, mOptions).getViews(); + View result = views.apply(mContext, null); + + TextView name = (TextView) result.findViewById(R.id.name); + assertEquals(name.getText(), NAME); + TextView subtext = (TextView) result.findViewById(R.id.subtext); + assertEquals(View.VISIBLE, result.findViewById(R.id.subtext).getVisibility()); + assertEquals(subtext.getText(), SENDER); + assertEquals(View.GONE, result.findViewById(R.id.predefined_icon).getVisibility()); + // Has availability. + assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility()); + // Has person icon. + assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility()); + // Has notification content. + TextView statusContent = (TextView) result.findViewById(R.id.text_content); + assertEquals(View.VISIBLE, statusContent.getVisibility()); + assertEquals(statusContent.getText(), NOTIFICATION_CONTENT); + + // Subtract one from lines because sender is included. + assertThat(statusContent.getMaxLines()).isEqualTo(2); + + // Has a single message, no count shown. + assertEquals(View.GONE, result.findViewById(R.id.messages_count).getVisibility()); + + mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH, + getSizeInDp(R.dimen.required_width_for_medium) - 1); + RemoteViews smallView = new PeopleTileViewHelper(mContext, + tileWithStatusAndNotification, 0, mOptions).getViews(); + View smallResult = smallView.apply(mContext, null); + + // Show icon instead of name. + assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility()); + assertEquals(View.VISIBLE, + smallResult.findViewById(R.id.predefined_icon).getVisibility()); + // Has person icon. + assertEquals(View.VISIBLE, + smallResult.findViewById(R.id.person_icon).getVisibility()); + + // Has a single message, no count shown. + assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility()); + + mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH, + getSizeInDp(R.dimen.required_width_for_large)); + mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH, + getSizeInDp(R.dimen.required_height_for_large)); + RemoteViews largeView = new PeopleTileViewHelper(mContext, + tileWithStatusAndNotification, 0, mOptions).getViews(); + View largeResult = largeView.apply(mContext, null); + + name = (TextView) largeResult.findViewById(R.id.name); + assertEquals(name.getText(), NAME); + subtext = (TextView) largeResult.findViewById(R.id.subtext); + assertEquals(View.VISIBLE, largeResult.findViewById(R.id.subtext).getVisibility()); + assertEquals(subtext.getText(), SENDER); + assertEquals(View.GONE, largeResult.findViewById(R.id.predefined_icon).getVisibility()); + // Has availability. + assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility()); + // Has person icon. + View personIcon = largeResult.findViewById(R.id.person_icon); + assertEquals(View.VISIBLE, personIcon.getVisibility()); + // Has notification content. + statusContent = (TextView) largeResult.findViewById(R.id.text_content); + assertEquals(View.VISIBLE, statusContent.getVisibility()); + assertEquals(statusContent.getText(), NOTIFICATION_CONTENT); + + // Subtract one from lines because sender is included. + assertThat(statusContent.getMaxLines()).isEqualTo(2); + + // Has a single message, no count shown. + assertEquals(View.GONE, largeResult.findViewById(R.id.messages_count).getVisibility()); + + } + + @Test public void testCreateRemoteViewsWithNotificationTemplateTwoMessages() { PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE.toBuilder() .setNotificationDataUri(null) 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 725e5d4523a7..411fb02ba87a 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 @@ -1201,7 +1201,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { .setPackageName(TEST_PACKAGE_A) .setUserHandle(new UserHandle(0)) .build(); - PeopleSpaceTile actual = mManager.augmentTileFromNotifications(tile, EMPTY_STRING, + PeopleTileKey key = new PeopleTileKey(tile); + PeopleSpaceTile actual = mManager.augmentTileFromNotifications(tile, key, EMPTY_STRING, Map.of(new PeopleTileKey(mNotificationEntry), new HashSet<>(Collections.singleton(mNotificationEntry)))); @@ -1216,8 +1217,9 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { .setPackageName(TEST_PACKAGE_A) .setUserHandle(new UserHandle(0)) .build(); + PeopleTileKey key = new PeopleTileKey(tile); PeopleSpaceTile actual = mManager - .augmentTileFromNotifications(tile, EMPTY_STRING, + .augmentTileFromNotifications(tile, key, EMPTY_STRING, Map.of(new PeopleTileKey(mNotificationEntry), new HashSet<>(Collections.singleton(mNotificationEntry)))); diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt index 05a1e4ff474d..03248f7e3a70 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt @@ -179,6 +179,9 @@ class PrivacyDialogControllerTest : SysuiTestCase() { @Test fun testShowDialogShowsDialog() { + val usage = createMockPermGroupUsage() + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) + controller.showDialog(context) exhaustExecutors() @@ -186,7 +189,17 @@ class PrivacyDialogControllerTest : SysuiTestCase() { } @Test + fun testDontShowEmptyDialog() { + controller.showDialog(context) + exhaustExecutors() + + verify(dialog, never()).show() + } + + @Test fun testHideDialogDismissesDialogIfShown() { + val usage = createMockPermGroupUsage() + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) controller.showDialog(context) exhaustExecutors() @@ -202,6 +215,8 @@ class PrivacyDialogControllerTest : SysuiTestCase() { @Test fun testHideDialogNoopAfterDismissed() { + val usage = createMockPermGroupUsage() + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) controller.showDialog(context) exhaustExecutors() @@ -214,6 +229,8 @@ class PrivacyDialogControllerTest : SysuiTestCase() { @Test fun testShowForAllUsers() { + val usage = createMockPermGroupUsage() + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) controller.showDialog(context) exhaustExecutors() @@ -439,7 +456,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { controller.showDialog(context) exhaustExecutors() - assertThat(dialogProvider.list).isEmpty() + verify(dialog, never()).show() } @Test @@ -467,11 +484,13 @@ class PrivacyDialogControllerTest : SysuiTestCase() { controller.showDialog(context) exhaustExecutors() - assertThat(dialogProvider.list).isEmpty() + verify(dialog, never()).show() } @Test fun testStartActivityCorrectIntent() { + val usage = createMockPermGroupUsage() + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) controller.showDialog(context) exhaustExecutors() @@ -488,6 +507,8 @@ class PrivacyDialogControllerTest : SysuiTestCase() { @Test fun testStartActivityCorrectIntent_enterpriseUser() { + val usage = createMockPermGroupUsage() + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) controller.showDialog(context) exhaustExecutors() @@ -501,6 +522,8 @@ class PrivacyDialogControllerTest : SysuiTestCase() { @Test fun testStartActivitySuccess() { + val usage = createMockPermGroupUsage() + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) controller.showDialog(context) exhaustExecutors() @@ -514,6 +537,8 @@ class PrivacyDialogControllerTest : SysuiTestCase() { @Test fun testStartActivityFailure() { + val usage = createMockPermGroupUsage() + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) controller.showDialog(context) exhaustExecutors() 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 21fec913f88c..d35597f799ee 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java @@ -42,7 +42,7 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.globalactions.GlobalActionsDialogLite; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.settings.UserTracker; -import com.android.systemui.statusbar.phone.MultiUserSwitch; +import com.android.systemui.statusbar.phone.MultiUserSwitchController; import com.android.systemui.statusbar.phone.SettingsButton; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.UserInfoController; @@ -90,7 +90,7 @@ public class QSFooterViewControllerTest extends LeakCheckedTest { @Mock private View mEdit; @Mock - private MultiUserSwitch mMultiUserSwitch; + private MultiUserSwitchController mMultiUserSwitchController; @Mock private View mPowerMenuLiteView; @Mock @@ -116,12 +116,11 @@ public class QSFooterViewControllerTest extends LeakCheckedTest { when(mView.findViewById(R.id.settings_button)).thenReturn(mSettingsButton); 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, + mMultiUserSwitchController, mQuickQSPanelController, mFakeTunerService, mMetricsLogger, new FalsingManagerFake(), false, mGlobalActionsDialog); mController.init(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java index 4ee639b6928f..234dec274c0c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java @@ -81,10 +81,10 @@ public class QSSecurityFooterTest extends SysuiTestCase { private static final String PARENTAL_CONTROLS_LABEL = "Parental Control App"; private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("TestDPC", "Test"); + private static final int DEFAULT_ICON_ID = R.drawable.ic_info_outline; private ViewGroup mRootView; private TextView mFooterText; - private TestableImageView mFooterIcon; private TestableImageView mPrimaryFooterIcon; private QSSecurityFooter mFooter; @Mock @@ -101,11 +101,10 @@ public class QSSecurityFooterTest extends SysuiTestCase { when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class)); mRootView = (ViewGroup) new LayoutInflaterBuilder(mContext) .replace("ImageView", TestableImageView.class) - .build().inflate(R.layout.quick_settings_footer, null, false); + .build().inflate(R.layout.quick_settings_security_footer, null, false); mFooter = new QSSecurityFooter(mRootView, mUserTracker, new Handler(looper), mActivityStarter, mSecurityController, looper); mFooterText = mRootView.findViewById(R.id.footer_text); - mFooterIcon = mRootView.findViewById(R.id.footer_icon); mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon); mFooter.setHostEnvironment(null); @@ -135,10 +134,8 @@ public class QSSecurityFooterTest extends SysuiTestCase { assertEquals(mContext.getString(R.string.quick_settings_disclosure_management), mFooterText.getText()); assertEquals(View.VISIBLE, mRootView.getVisibility()); - assertEquals(View.VISIBLE, mFooterIcon.getVisibility()); - assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility()); - // -1 == never set. - assertEquals(-1, mFooterIcon.getLastImageResource()); + assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); + assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); } @Test @@ -153,10 +150,8 @@ public class QSSecurityFooterTest extends SysuiTestCase { MANAGING_ORGANIZATION), mFooterText.getText()); assertEquals(View.VISIBLE, mRootView.getVisibility()); - assertEquals(View.VISIBLE, mFooterIcon.getVisibility()); - assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility()); - // -1 == never set. - assertEquals(-1, mFooterIcon.getLastImageResource()); + assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); + assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); } @Test @@ -174,10 +169,8 @@ public class QSSecurityFooterTest extends SysuiTestCase { R.string.quick_settings_financed_disclosure_named_management, MANAGING_ORGANIZATION), mFooterText.getText()); assertEquals(View.VISIBLE, mRootView.getVisibility()); - assertEquals(View.VISIBLE, mFooterIcon.getVisibility()); - assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility()); - // -1 == never set. - assertEquals(-1, mFooterIcon.getLastImageResource()); + assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); + assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); } @Test @@ -204,10 +197,8 @@ public class QSSecurityFooterTest extends SysuiTestCase { TestableLooper.get(this).processAllMessages(); assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring), mFooterText.getText()); - assertEquals(View.VISIBLE, mFooterIcon.getVisibility()); - assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility()); - // -1 == never set. - assertEquals(-1, mFooterIcon.getLastImageResource()); + assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); + assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); // Same situation, but with organization name set when(mSecurityController.getDeviceOwnerOrganizationName()) @@ -255,9 +246,8 @@ public class QSSecurityFooterTest extends SysuiTestCase { assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_named_vpn, VPN_PACKAGE), mFooterText.getText()); - assertEquals(View.VISIBLE, mFooterIcon.getVisibility()); - assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility()); - assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource()); + assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); + assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource()); // Same situation, but with organization name set when(mSecurityController.getDeviceOwnerOrganizationName()) @@ -282,9 +272,8 @@ public class QSSecurityFooterTest extends SysuiTestCase { TestableLooper.get(this).processAllMessages(); assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_vpns), mFooterText.getText()); - assertEquals(View.VISIBLE, mFooterIcon.getVisibility()); - assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility()); - assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource()); + assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); + assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource()); // Same situation, but with organization name set when(mSecurityController.getDeviceOwnerOrganizationName()) @@ -306,9 +295,8 @@ public class QSSecurityFooterTest extends SysuiTestCase { mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - assertEquals(View.VISIBLE, mFooterIcon.getVisibility()); - assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility()); - assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource()); + assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); + assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource()); assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring), mFooterText.getText()); } @@ -320,8 +308,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - // -1 == never set. - assertEquals(-1, mFooterIcon.getLastImageResource()); + assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); assertEquals(mContext.getString( R.string.quick_settings_disclosure_managed_profile_monitoring), mFooterText.getText()); @@ -345,8 +332,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - // -1 == never set. - assertEquals(-1, mFooterIcon.getLastImageResource()); + assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); assertEquals(mContext.getString(R.string.quick_settings_disclosure_monitoring), mFooterText.getText()); } @@ -359,7 +345,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource()); + assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource()); assertEquals(mContext.getString(R.string.quick_settings_disclosure_vpns), mFooterText.getText()); } @@ -371,7 +357,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource()); + assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource()); assertEquals(mContext.getString( R.string.quick_settings_disclosure_managed_profile_named_vpn, VPN_PACKAGE_2), @@ -412,7 +398,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource()); + assertEquals(R.drawable.stat_sys_vpn_ic, mPrimaryFooterIcon.getLastImageResource()); assertEquals(mContext.getString(R.string.quick_settings_disclosure_named_vpn, VPN_PACKAGE), mFooterText.getText()); @@ -648,12 +634,12 @@ public class QSSecurityFooterTest extends SysuiTestCase { assertEquals(testDrawable, mPrimaryFooterIcon.getDrawable()); - // Ensure the primary icon is set to gone when parental controls is disabled. + // Ensure the primary icon is back to default after parental controls are gone when(mSecurityController.isParentalControlsEnabled()).thenReturn(false); mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility()); + assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java index 2f28b13ec280..5cdad05e43f5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java @@ -207,7 +207,25 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { } @Test - public void testHandleClick_hasCards_startWalletActivity() { + public void testHandleClick_hasCards_deviceLocked_startWalletActivity() { + when(mKeyguardStateController.isUnlocked()).thenReturn(false); + setUpWalletCard(/* hasCard= */ true); + + mTile.handleClick(null /* view */); + mTestableLooper.processAllMessages(); + + verify(mSpiedContext).startActivity(mIntentCaptor.capture()); + + Intent nextStartedIntent = mIntentCaptor.getValue(); + String walletClassName = "com.android.systemui.wallet.ui.WalletActivity"; + + assertNotNull(nextStartedIntent); + assertThat(nextStartedIntent.getComponent().getClassName()).isEqualTo(walletClassName); + } + + @Test + public void testHandleClick_hasCards_deviceUnlocked_startWalletActivity() { + when(mKeyguardStateController.isUnlocked()).thenReturn(true); setUpWalletCard(/* hasCard= */ true); mTile.handleClick(null /* view */); @@ -226,7 +244,7 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { @Test public void testHandleUpdateState_updateLabelAndIcon() { QSTile.State state = new QSTile.State(); - QSTile.Icon icon = QSTileImpl.ResourceIcon.get(R.drawable.ic_qs_wallet); + QSTile.Icon icon = QSTileImpl.ResourceIcon.get(R.drawable.ic_wallet_lockscreen); mTile.handleUpdateState(state, null); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt index f48b3fc51e82..af75f2c66195 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt @@ -28,6 +28,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.util.UserIcons import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.qs.QSUserSwitcherEvent import com.android.systemui.statusbar.policy.UserSwitcherController import org.junit.Assert.assertEquals @@ -53,6 +54,7 @@ class UserDetailViewAdapterTest : SysuiTestCase() { @Mock private lateinit var mInflatedUserDetailItemView: UserDetailItemView @Mock private lateinit var mUserInfo: UserInfo @Mock private lateinit var mLayoutInflater: LayoutInflater + private var falsingManagerFake: FalsingManagerFake = FalsingManagerFake() private lateinit var adapter: UserDetailView.Adapter private lateinit var uiEventLogger: UiEventLoggerFake private lateinit var mPicture: Bitmap @@ -65,7 +67,8 @@ class UserDetailViewAdapterTest : SysuiTestCase() { mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, mLayoutInflater) `when`(mLayoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean())) .thenReturn(mInflatedUserDetailItemView) - adapter = UserDetailView.Adapter(mContext, mUserSwitcherController, uiEventLogger) + adapter = UserDetailView.Adapter(mContext, mUserSwitcherController, uiEventLogger, + falsingManagerFake) mPicture = UserIcons.convertToBitmap(mContext.getDrawable(R.drawable.ic_avatar_user)) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt index 45a7d0a54155..a0c3ed992115 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt @@ -69,7 +69,6 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { @Mock private lateinit var shadeSpring: NotificationShadeDepthController.DepthAnimation @Mock private lateinit var shadeAnimation: NotificationShadeDepthController.DepthAnimation @Mock private lateinit var globalActionsSpring: NotificationShadeDepthController.DepthAnimation - @Mock private lateinit var brightnessSpring: NotificationShadeDepthController.DepthAnimation @Mock private lateinit var listener: NotificationShadeDepthController.DepthListener @Mock private lateinit var dozeParameters: DozeParameters @JvmField @Rule val mockitoRule = MockitoJUnit.rule() @@ -97,7 +96,6 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { notificationShadeWindowController, dozeParameters, dumpManager) notificationShadeDepthController.shadeSpring = shadeSpring notificationShadeDepthController.shadeAnimation = shadeAnimation - notificationShadeDepthController.brightnessMirrorSpring = brightnessSpring notificationShadeDepthController.globalActionsSpring = globalActionsSpring notificationShadeDepthController.root = root @@ -245,31 +243,6 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { } @Test - fun brightnessMirrorVisible_whenVisible() { - notificationShadeDepthController.brightnessMirrorVisible = true - verify(brightnessSpring).animateTo(eq(maxBlur), any()) - } - - @Test - fun brightnessMirrorVisible_whenHidden() { - notificationShadeDepthController.brightnessMirrorVisible = false - verify(brightnessSpring).animateTo(eq(0), any()) - } - - @Test - fun brightnessMirror_hidesShadeBlur() { - // Brightness mirror is fully visible - `when`(brightnessSpring.ratio).thenReturn(1f) - // And shade is blurred - `when`(shadeSpring.radius).thenReturn(maxBlur) - `when`(shadeAnimation.radius).thenReturn(maxBlur) - - notificationShadeDepthController.updateBlurCallback.doFrame(0) - verify(notificationShadeWindowController).setBackgroundBlurRadius(0) - verify(blurUtils).applyBlur(eq(viewRootImpl), eq(0)) - } - - @Test fun setNotificationLaunchAnimationParams_schedulesFrame() { val animProgress = ExpandAnimationParameters() animProgress.linearProgress = 0.5f diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt index 5e783a53a1e1..03744b78e8d5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.charging -import android.content.Context import android.testing.AndroidTestingRunner import android.view.View import android.view.WindowManager @@ -26,7 +25,7 @@ import com.android.systemui.statusbar.FeatureFlags import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.ConfigurationController -import com.android.systemui.util.mockito.capture +import com.android.systemui.util.time.FakeSystemClock import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -37,6 +36,7 @@ import org.mockito.Mockito.`when` import org.mockito.Mockito.any import org.mockito.Mockito.eq import org.mockito.Mockito.reset +import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -50,6 +50,7 @@ class WiredChargingRippleControllerTest : SysuiTestCase() { @Mock private lateinit var configurationController: ConfigurationController @Mock private lateinit var rippleView: ChargingRippleView @Mock private lateinit var windowManager: WindowManager + private val systemClock = FakeSystemClock() @Before fun setUp() { @@ -57,9 +58,8 @@ class WiredChargingRippleControllerTest : SysuiTestCase() { `when`(featureFlags.isChargingRippleEnabled).thenReturn(true) controller = WiredChargingRippleController( commandRegistry, batteryController, configurationController, - featureFlags, context) + featureFlags, context, windowManager, systemClock) controller.rippleView = rippleView // Replace the real ripple view with a mock instance - context.addMockSystemService(Context.WINDOW_SERVICE, windowManager) } @Test @@ -71,8 +71,8 @@ class WiredChargingRippleControllerTest : SysuiTestCase() { // Verify ripple added to window manager. captor.value.onBatteryLevelChanged( 0 /* unusedBatteryLevel */, - false /* plugged in */, - true /* charging */) + true /* plugged in */, + false /* charging */) val attachListenerCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java) verify(rippleView).addOnAttachStateChangeListener(attachListenerCaptor.capture()) @@ -103,4 +103,37 @@ class WiredChargingRippleControllerTest : SysuiTestCase() { captor.value.onUiModeChanged() verify(rippleView).setColor(ArgumentMatchers.anyInt()) } + + @Test + fun testDebounceRipple() { + var time: Long = 0 + systemClock.setElapsedRealtime(time) + + controller.startRippleWithDebounce() + verify(rippleView).addOnAttachStateChangeListener(ArgumentMatchers.any()) + + reset(rippleView) + // Wait a short while and trigger. + time += 100 + systemClock.setElapsedRealtime(time) + controller.startRippleWithDebounce() + + // Verify the ripple is debounced. + verify(rippleView, never()).addOnAttachStateChangeListener(ArgumentMatchers.any()) + + // Trigger many times. + for (i in 0..100) { + time += 100 + systemClock.setElapsedRealtime(time) + controller.startRippleWithDebounce() + } + // Verify all attempts are debounced. + verify(rippleView, never()).addOnAttachStateChangeListener(ArgumentMatchers.any()) + + // Wait a long while and trigger. + systemClock.setElapsedRealtime(time + 500000) + controller.startRippleWithDebounce() + // Verify that ripple is triggered. + verify(rippleView).addOnAttachStateChangeListener(ArgumentMatchers.any()) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt index c832fe481f74..bdd4a01a9766 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt @@ -21,6 +21,8 @@ import android.app.NotificationChannel import android.app.NotificationManager.IMPORTANCE_DEFAULT import android.app.NotificationManager.IMPORTANCE_HIGH import android.app.NotificationManager.IMPORTANCE_LOW +import android.app.PendingIntent +import android.app.Person import android.os.SystemClock import android.service.notification.NotificationListenerService.RankingMap import android.testing.AndroidTestingRunner @@ -408,6 +410,74 @@ class NotificationRankingManagerTest : SysuiTestCase() { assertThat(b.bucket).isEqualTo(BUCKET_FOREGROUND_SERVICE) } + @Test + fun testSort_importantCall() { + whenever(sectionsManager.isFilteringEnabled()).thenReturn(true) + + val a = NotificationEntryBuilder() + .setImportance(IMPORTANCE_HIGH) + .setPkg("pkg") + .setOpPkg("pkg") + .setTag("tag") + .setNotification( + Notification.Builder(mContext, "test") + .build()) + .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) + .setUser(mContext.getUser()) + .setOverrideGroupKey("") + .build() + + val b = NotificationEntryBuilder() + .setImportance(IMPORTANCE_DEFAULT) // high priority + .setPkg("pkg2") + .setOpPkg("pkg2") + .setTag("tag") + .setNotification(mock(Notification::class.java).also { notif -> + whenever(notif.isForegroundService).thenReturn(true) + whenever(notif.isColorized).thenReturn(true) + }) + .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) + .setUser(mContext.getUser()) + .setOverrideGroupKey("") + .build() + + val cN = Notification.Builder(mContext, "test") + .setStyle(Notification.MessagingStyle("")) + .build() + val c = NotificationEntryBuilder() + .setImportance(IMPORTANCE_HIGH) + .setPkg("pkg") + .setOpPkg("pkg") + .setTag("tag") + .setNotification(cN) + .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) + .setUser(mContext.user) + .setOverrideGroupKey("") + .build() + + val dN = Notification.Builder(mContext, "test") + .setStyle(Notification.CallStyle.forOngoingCall( + Person.Builder().setName("caller").build(), + mock(PendingIntent::class.java))) + .build() + val d = NotificationEntryBuilder() + .setImportance(IMPORTANCE_DEFAULT) // high priority + .setPkg("pkg2") + .setOpPkg("pkg2") + .setTag("tag") + .setNotification(dN) + .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) + .setUser(mContext.user) + .setOverrideGroupKey("") + .build() + whenever(personNotificationIdentifier.getPeopleNotificationType(a)) + .thenReturn(TYPE_IMPORTANT_PERSON) + + assertThat(rankingManager.updateRanking(null, listOf(a, b, c, d), "test")) + .containsExactly(b, d, c, a) + assertThat(d.bucket).isEqualTo(BUCKET_FOREGROUND_SERVICE) + } + internal class TestableNotificationRankingManager( mediaManager: Lazy<NotificationMediaManager>, groupManager: NotificationGroupManagerLegacy, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java index 02e2e4c793bc..152ba90858d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java @@ -53,6 +53,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { private boolean mHasVisibleNotifs; private float mQsExpansion; private int mCutoutTopInset = 0; // in pixels + private boolean mIsSplitShade = false; @Before public void setUp() { @@ -265,6 +266,19 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { } @Test + public void notifPositionAlignedWithClockInSplitShadeMode() { + // GIVEN on lock screen and split shade mode + givenLockScreen(); + mIsSplitShade = true; + mPreferredClockY = 100; + mHasCustomClock = true; + // WHEN the position algorithm is run + positionClock(); + // THEN the notif padding DOESN'T adjust for keyguard status height. + assertThat(mClockPosition.stackScrollerPadding).isEqualTo(mPreferredClockY); + } + + @Test public void notifPositionWithLargeClockOnLockScreen() { // GIVEN on lock screen and clock has a nonzero height givenLockScreen(); @@ -397,7 +411,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { 0 /* userSwitchHeight */, mPreferredClockY, 0 /* userSwitchPreferredY */, mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */, 0 /* unlockedStackScrollerPadding */, mQsExpansion, - mCutoutTopInset); + mCutoutTopInset, mIsSplitShade); mClockPositionAlgorithm.run(mClockPosition); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index cebf8be49150..4bac7625cfed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -75,6 +75,7 @@ import com.android.systemui.biometrics.AuthController; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.doze.DozeLog; +import com.android.systemui.media.KeyguardMediaController; import com.android.systemui.media.MediaDataManager; import com.android.systemui.media.MediaHierarchyManager; import com.android.systemui.qs.QSDetailDisplayer; @@ -240,6 +241,8 @@ public class NotificationPanelViewTest extends SysuiTestCase { private LockIconViewController mLockIconViewController; @Mock private QuickAccessWalletClient mQuickAccessWalletClient; + @Mock + private KeyguardMediaController mKeyguardMediaController; private SysuiStatusBarStateController mStatusBarStateController; private NotificationPanelViewController mNotificationPanelViewController; @@ -282,6 +285,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null); mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame)); mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller)); + mNotificationContainerParent.addView(newViewWithId(R.id.keyguard_status_view)); when(mView.findViewById(R.id.notification_container_parent)) .thenReturn(mNotificationContainerParent); FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder( @@ -346,6 +350,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { mLockIconViewController, mFeatureFlags, mQuickAccessWalletClient, + mKeyguardMediaController, new FakeExecutor(new FakeSystemClock())); mNotificationPanelViewController.initDependencies( mStatusBar, @@ -476,6 +481,20 @@ public class NotificationPanelViewTest extends SysuiTestCase { } @Test + public void testKeyguardStatusView_isAlignedToGuidelineInSplitShadeMode() { + mNotificationPanelViewController.updateResources(); + + assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd) + .isEqualTo(ConstraintSet.PARENT_ID); + + enableSplitShade(); + mNotificationPanelViewController.updateResources(); + + assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd) + .isEqualTo(R.id.qs_edge_guideline); + } + + @Test public void testSplitShadeLayout_isAlignedToGuideline() { enableSplitShade(); @@ -553,6 +572,36 @@ public class NotificationPanelViewTest extends SysuiTestCase { assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isFalse(); } + @Test + public void testSwipeWhileLocked_notifiesKeyguardState() { + mStatusBarStateController.setState(KEYGUARD); + + // Fling expanded (cancelling the keyguard exit swipe). We should notify keyguard state that + // the fling occurred and did not dismiss the keyguard. + mNotificationPanelViewController.flingToHeight( + 0f, true /* expand */, 1000f, 1f, false); + verify(mKeyguardStateController).notifyPanelFlingStart(false /* dismissKeyguard */); + + // Fling un-expanded, which is a keyguard exit fling when we're in KEYGUARD state. + mNotificationPanelViewController.flingToHeight( + 0f, false /* expand */, 1000f, 1f, false); + verify(mKeyguardStateController).notifyPanelFlingStart(true /* dismissKeyguard */); + } + + @Test + public void testCancelSwipeWhileLocked_notifiesKeyguardState() { + mStatusBarStateController.setState(KEYGUARD); + + mNotificationPanelViewController.setOverExpansion(100f, true); + + // Fling expanded (cancelling the keyguard exit swipe). We should notify keyguard state that + // the fling occurred and did not dismiss the keyguard. + mNotificationPanelViewController.flingToHeight( + 0f, true /* expand */, 1000f, 1f, false); + mNotificationPanelViewController.cancelHeightAnimator(); + verify(mKeyguardStateController).notifyPanelFlingEnd(); + } + private View newViewWithId(int id) { View view = new View(mContext); view.setId(id); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java index 4b8eec44ef4c..323843098a1a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java @@ -134,6 +134,19 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { } @Test + public void attach_animatingKeyguardAndSurface_wallpaperVisible() { + clearInvocations(mWindowManager); + when(mKeyguardViewMediator.isShowingAndNotOccluded()).thenReturn(true); + when(mKeyguardViewMediator + .isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) + .thenReturn(true); + mNotificationShadeWindowController.attach(); + + verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture()); + assertThat((mLayoutParameters.getValue().flags & FLAG_SHOW_WALLPAPER) != 0).isTrue(); + } + + @Test public void setBackgroundBlurRadius_expandedWithBlurs() { mNotificationShadeWindowController.setBackgroundBlurRadius(10); verify(mNotificationShadeWindowView).setVisibility(eq(View.VISIBLE)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 559ee6f29bb6..b6eb4923ee4a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -50,7 +50,6 @@ import com.android.systemui.DejankUtils; import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; import com.android.systemui.scrim.ScrimView; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; @@ -107,8 +106,6 @@ public class ScrimControllerTest extends SysuiTestCase { private DockManager mDockManager; @Mock private ConfigurationController mConfigurationController; - @Mock - private FeatureFlags mFeatureFlags; private static class AnimatorListener implements Animator.AnimatorListener { @@ -217,14 +214,12 @@ public class ScrimControllerTest extends SysuiTestCase { when(mDelayedWakeLockBuilder.setTag(any(String.class))) .thenReturn(mDelayedWakeLockBuilder); when(mDelayedWakeLockBuilder.build()).thenReturn(mWakeLock); - when(mFeatureFlags.isShadeOpaque()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(false); mScrimController = new ScrimController(mLightBarController, mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder, new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, - mDockManager, mConfigurationController, mFeatureFlags, - new FakeExecutor(new FakeSystemClock())); + mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock())); mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible); mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront, mScrimForBubble); @@ -602,7 +597,7 @@ public class ScrimControllerTest extends SysuiTestCase { assertScrimTinted(Map.of( mScrimInFront, false, mScrimBehind, false, - mScrimForBubble, false + mScrimForBubble, true )); // Front scrim should be transparent diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 11f96c87c0e5..545e2e08ec07 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -86,6 +86,7 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.keyguard.DismissCallbackRegistry; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; @@ -145,7 +146,6 @@ import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.tuner.TunerService; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.volume.VolumeComponent; @@ -268,9 +268,9 @@ public class StatusBarTest extends SysuiTestCase { @Mock private OngoingCallController mOngoingCallController; @Mock private SystemStatusAnimationScheduler mAnimationScheduler; @Mock private PrivacyDotViewController mDotViewController; - @Mock private TunerService mTunerService; @Mock private FeatureFlags mFeatureFlags; @Mock private IWallpaperManager mWallpaperManager; + @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private ShadeController mShadeController; private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private InitController mInitController = new InitController(); @@ -438,8 +438,8 @@ public class StatusBarTest extends SysuiTestCase { mOngoingCallController, mAnimationScheduler, mDotViewController, - mTunerService, - mFeatureFlags); + mFeatureFlags, + mKeyguardUnlockAnimationController); when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class), any(NotificationPanelViewController.class), any(BiometricUnlockController.class), any(ViewGroup.class), any(KeyguardBypassController.class))) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java index e57bbc1623f0..53a2efce9bb8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java @@ -143,4 +143,14 @@ public class KeyguardStateControllerTest extends SysuiTestCase { verify(callback).onUnlockedChanged(); } + @Test + public void testKeyguardDismissAmountCallbackInvoked() { + KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class); + mKeyguardStateController.addCallback(callback); + + mKeyguardStateController.notifyKeyguardDismissAmountChanged(100f, false); + + verify(callback).onKeyguardDismissAmountChanged(); + } + } 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 ab7cbf77f5ee..bfb98deda452 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 @@ -4,6 +4,7 @@ import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -309,6 +310,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { // Put RSSI in the middle of the range. rssi += amountPerLevel / 2; when(mVcnTransportInfo.getWifiInfo()).thenReturn(mWifiInfo); + when(mVcnTransportInfo.makeCopy(anyLong())).thenReturn(mVcnTransportInfo); when(mWifiInfo.getRssi()).thenReturn(rssi); when(mWifiInfo.isCarrierMerged()).thenReturn(true); when(mWifiInfo.getSubscriptionId()).thenReturn(1); @@ -318,6 +320,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { protected void setWifiStateForVcn(boolean connected, String ssid) { when(mVcnTransportInfo.getWifiInfo()).thenReturn(mWifiInfo); + when(mVcnTransportInfo.makeCopy(anyLong())).thenReturn(mVcnTransportInfo); when(mWifiInfo.getSSID()).thenReturn(ssid); when(mWifiInfo.isCarrierMerged()).thenReturn(true); when(mWifiInfo.getSubscriptionId()).thenReturn(1); diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java index d8271e8292be..db6164dcf8f9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java @@ -71,6 +71,10 @@ public class FakeSystemClock implements SystemClock { mCurrentTimeMillis = millis; } + public void setElapsedRealtime(long millis) { + mElapsedRealtime = millis; + } + /** * Advances the time tracked by the fake clock and notifies any listeners that the time has * changed (for example, an attached {@link FakeExecutor} may fire its pending runnables). diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java index 26cac290c9b5..5fb779adc5be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java @@ -92,4 +92,39 @@ public class FakeKeyguardStateController implements KeyguardStateController { public long calculateGoingToFullShadeDelay() { return 0; } + + @Override + public float getDismissAmount() { + return 0; + } + + @Override + public boolean isDismissingFromSwipe() { + return false; + } + + @Override + public boolean isFlingingToDismissKeyguard() { + return false; + } + + @Override + public boolean isFlingingToDismissKeyguardDuringSwipeGesture() { + return false; + } + + @Override + public boolean isSnappingKeyguardBackAfterSwipe() { + return false; + } + + @Override + public void notifyPanelFlingStart(boolean dismiss) { + + } + + @Override + public void notifyPanelFlingEnd() { + + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 9fc1df73d8b3..6e2e4cb9ecfa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -112,6 +112,7 @@ import com.android.wm.shell.bubbles.BubbleOverflow; import com.android.wm.shell.bubbles.BubbleStackView; import com.android.wm.shell.bubbles.BubbleViewInfoTask; import com.android.wm.shell.bubbles.Bubbles; +import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerImpl; @@ -315,6 +316,7 @@ public class BubblesTest extends SysuiTestCase { mTaskStackListener, mShellTaskOrganizer, mPositioner, + mock(DisplayController.class), syncExecutor, mock(Handler.class)); mBubbleController.setExpandListener(mBubbleExpandListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java index 89825d240ec1..9339f81940d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java @@ -92,6 +92,7 @@ import com.android.wm.shell.bubbles.BubbleLogger; import com.android.wm.shell.bubbles.BubbleOverflow; import com.android.wm.shell.bubbles.BubbleStackView; import com.android.wm.shell.bubbles.Bubbles; +import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerImpl; @@ -259,6 +260,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { mTaskStackListener, mShellTaskOrganizer, mPositioner, + mock(DisplayController.class), syncExecutor, mock(Handler.class)); mBubbleController.setExpandListener(mBubbleExpandListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java index a9a558dca577..cd5aa9a3f9dc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java @@ -29,6 +29,7 @@ import com.android.wm.shell.bubbles.BubbleData; import com.android.wm.shell.bubbles.BubbleDataRepository; import com.android.wm.shell.bubbles.BubbleLogger; import com.android.wm.shell.bubbles.BubblePositioner; +import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerImpl; @@ -51,12 +52,13 @@ public class TestableBubbleController extends BubbleController { TaskStackListenerImpl taskStackListener, ShellTaskOrganizer shellTaskOrganizer, BubblePositioner positioner, + DisplayController displayController, ShellExecutor shellMainExecutor, Handler shellMainHandler) { super(context, data, Runnable::run, floatingContentCoordinator, dataRepository, statusBarService, windowManager, windowManagerShellWrapper, launcherApps, - bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, shellMainExecutor, - shellMainHandler); + bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController, + shellMainExecutor, shellMainHandler); setInflateSynchronously(true); initialize(); } diff --git a/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp b/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp index a18ebb3eaea5..690d0a0ecda3 100644 --- a/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp +++ b/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp @@ -26,6 +26,5 @@ package { runtime_resource_overlay { name: "IconPackVictorThemePickerOverlay", theme: "IconPackVictorThemePicker", - certificate: "platform", product_specific: true, } diff --git a/services/Android.bp b/services/Android.bp index 20b89de7f2a6..2281a159f6f7 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -180,68 +180,12 @@ stubs_defaults { " --hide-package com.google.android.startop.iorap" + " --hide DeprecationMismatch" + " --hide HiddenTypedefConstant", - visibility: ["//visibility:private"], + visibility: ["//frameworks/base:__subpackages__"], filter_packages: ["com.android."], } droidstubs { - name: "services-stubs.sources", - srcs: [":services-all-sources"], - defaults: ["services-stubs-default"], - check_api: { - current: { - api_file: "api/current.txt", - removed_api_file: "api/removed.txt", - }, - last_released: { - api_file: ":android.api.system-server.latest", - removed_api_file: ":removed.api.system-server.latest", - baseline_file: ":android-incompatibilities.api.system-server.latest", - }, - api_lint: { - enabled: true, - new_since: ":android.api.system-server.latest", - baseline_file: "api/lint-baseline.txt", - }, - }, - dists: [ - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/system-server/api", - dest: "android.txt", - tag: ".api.txt", - }, - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/system-server/api", - dest: "removed.txt", - tag: ".removed-api.txt", - }, - ], -} - -java_library { - name: "android_system_server_stubs_current", - defaults: ["android_stubs_dists_default"], - srcs: [":services-stubs.sources"], - installable: false, - static_libs: ["android_module_lib_stubs_current"], - sdk_version: "none", - system_modules: "none", - java_version: "1.8", - dist: { - dir: "apistubs/android/system-server", - }, -} - -droidstubs { - name: "services-non-updatable-stubs.sources", + name: "services-non-updatable-stubs", srcs: [":services-non-updatable-sources"], defaults: ["services-stubs-default"], check_api: { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java index fd355d8da341..dc2628f0bc0b 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java @@ -16,6 +16,8 @@ package com.android.server.accessibility; +import static android.content.pm.PackageManagerInternal.PACKAGE_INSTALLER; + import android.Manifest; import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.NonNull; @@ -24,7 +26,9 @@ import android.app.AppOpsManager; import android.appwidget.AppWidgetManagerInternal; import android.content.ComponentName; import android.content.Context; +import android.content.pm.InstallSourceInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; @@ -33,11 +37,13 @@ import android.os.IBinder; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; import android.view.accessibility.AccessibilityEvent; import com.android.internal.util.ArrayUtils; +import com.android.server.LocalServices; import libcore.util.EmptyArray; @@ -666,13 +672,66 @@ public class AccessibilitySecurityPolicy { /** * Identifies whether the accessibility service is true and designed for accessibility. An - * accessibility service is considered as accessibility category if - * {@link AccessibilityServiceInfo#isAccessibilityTool} is true. + * accessibility service is considered as accessibility category if meets all conditions below: + * <ul> + * <li> {@link AccessibilityServiceInfo#isAccessibilityTool} is true</li> + * <li> is installed from the trusted install source</li> + * </ul> * * @param serviceInfo The accessibility service's serviceInfo. * @return Returns true if it is a true accessibility service. */ public boolean isA11yCategoryService(AccessibilityServiceInfo serviceInfo) { - return serviceInfo.isAccessibilityTool(); + if (!serviceInfo.isAccessibilityTool()) { + return false; + } + if (!serviceInfo.getResolveInfo().serviceInfo.applicationInfo.isSystemApp()) { + return hasTrustedSystemInstallSource( + serviceInfo.getResolveInfo().serviceInfo.packageName); + } + return true; + } + + /** Returns true if the {@code installedPackage} is installed from the trusted install source. + */ + private boolean hasTrustedSystemInstallSource(String installedPackage) { + try { + InstallSourceInfo installSourceInfo = mPackageManager.getInstallSourceInfo( + installedPackage); + if (installSourceInfo == null) { + return false; + } + final String installSourcePackageName = installSourceInfo.getInitiatingPackageName(); + if (installSourcePackageName == null || !mPackageManager.getPackageInfo( + installSourcePackageName, + 0).applicationInfo.isSystemApp()) { + return false; + } + return isTrustedInstallSource(installSourcePackageName); + } catch (PackageManager.NameNotFoundException e) { + Slog.w(LOG_TAG, "can't find the package's install source:" + installedPackage); + } + return false; + } + + /** Returns true if the {@code installerPackage} is a trusted install source. */ + private boolean isTrustedInstallSource(String installerPackage) { + final String[] allowedInstallingSources = mContext.getResources().getStringArray( + com.android.internal.R.array + .config_accessibility_allowed_install_source); + + if (allowedInstallingSources.length == 0) { + //Filters unwanted default installers if no allowed install sources. + String defaultInstaller = ArrayUtils.firstOrNull(LocalServices.getService( + PackageManagerInternal.class).getKnownPackageNames(PACKAGE_INSTALLER, + mCurrentUserId)); + return !TextUtils.equals(defaultInstaller, installerPackage); + } + for (int i = 0; i < allowedInstallingSources.length; i++) { + if (TextUtils.equals(allowedInstallingSources[i], installerPackage)) { + return true; + } + } + return false; } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillUriGrantsManager.java b/services/autofill/java/com/android/server/autofill/AutofillUriGrantsManager.java index 801be5e48d8b..51e023d545fa 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillUriGrantsManager.java +++ b/services/autofill/java/com/android/server/autofill/AutofillUriGrantsManager.java @@ -20,6 +20,8 @@ import static android.content.ContentResolver.SCHEME_CONTENT; import static com.android.server.autofill.Helper.sVerbose; +import static java.lang.Integer.toHexString; + import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.IUriGrantsManager; @@ -33,32 +35,16 @@ import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Pair; import android.util.Slog; -import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; -import com.android.server.uri.UriGrantsManagerInternal; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Set; +import com.android.server.wm.ActivityTaskManagerInternal; /** - * Grants and revokes URI permissions for content-based autofill suggestions. + * Grants URI permissions for content-based autofill suggestions. * - * <p>Note that the system cannot just hand out grants directly; it must always do so on behalf of - * an owner (see {@link com.android.server.uri.UriGrantsManagerService}). For autofill, the owner - * is the autofill service provider that creates a given autofill suggestion containing a content - * URI. Therefore, this manager class must be instantiated with the service uid of the provider for - * which it will manage URI grants. - * - * <p>To dump the state of this class, use {@code adb shell dumpsys autofill}. + * <p>URI permissions granted by this class are tied to the activity being filled. When the + * activity finishes, its URI grants are automatically revoked. * * <p>To dump all active URI permissions, use {@code adb shell dumpsys activity permissions}. */ @@ -69,26 +55,10 @@ final class AutofillUriGrantsManager { @UserIdInt private final int mSourceUserId; @NonNull - private final IBinder mPermissionOwner; - @NonNull - private final UriGrantsManagerInternal mUgmInternal; + private final ActivityTaskManagerInternal mActivityTaskMgrInternal; @NonNull private final IUriGrantsManager mUgm; - // We use a local lock here for simplicity, since the synchronized code does not depend on - // any other resources (the "hold and wait" condition required for deadlock is not present). - // If this changes in the future, instead of using a local lock this should be updated to - // use the shared lock from AutofillManagerServiceImpl. - @NonNull - private final Object mLock; - - // Tracks the URIs that have been granted to each package. For each URI, the map stores the - // activities that triggered the grant. This allows revoking permissions only once all - // activities that triggered the grant are finished. - @NonNull - @GuardedBy("mLock") - private final ArrayMap<String, List<Pair<Uri, String>>> mActiveGrantsByPackage; - /** * Creates a new instance of the manager. * @@ -99,159 +69,60 @@ final class AutofillUriGrantsManager { AutofillUriGrantsManager(int serviceUid) { mSourceUid = serviceUid; mSourceUserId = UserHandle.getUserId(mSourceUid); - mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class); - mPermissionOwner = mUgmInternal.newUriPermissionOwner("autofill-" + serviceUid); + mActivityTaskMgrInternal = LocalServices.getService(ActivityTaskManagerInternal.class); mUgm = UriGrantsManager.getService(); - mLock = new Object(); - mActiveGrantsByPackage = new ArrayMap<>(0); } public void grantUriPermissions(@NonNull ComponentName targetActivity, - @UserIdInt int targetUserId, @NonNull ClipData clip) { - String targetPkg = targetActivity.getPackageName(); + @NonNull IBinder targetActivityToken, @UserIdInt int targetUserId, + @NonNull ClipData clip) { + final String targetPkg = targetActivity.getPackageName(); + final IBinder permissionOwner = + mActivityTaskMgrInternal.getUriPermissionOwnerForActivity(targetActivityToken); + if (permissionOwner == null) { + Slog.w(TAG, "Can't grant URI permissions, because the target activity token is invalid:" + + " clip=" + clip + + ", targetActivity=" + targetActivity + ", targetUserId=" + targetUserId + + ", targetActivityToken=" + toHexString(targetActivityToken.hashCode())); + return; + } for (int i = 0; i < clip.getItemCount(); i++) { ClipData.Item item = clip.getItemAt(i); Uri uri = item.getUri(); if (uri == null || !SCHEME_CONTENT.equals(uri.getScheme())) { continue; } - if (grantUriPermissions(targetPkg, targetUserId, uri)) { - addToActiveGrants(uri, targetActivity); - } - } - } - - public void revokeUriPermissions(@NonNull ComponentName targetActivity, - @UserIdInt int targetUserId) { - String targetPkg = targetActivity.getPackageName(); - Set<Uri> urisWhoseGrantsShouldBeRevoked = removeFromActiveGrants(targetActivity); - for (Uri uri : urisWhoseGrantsShouldBeRevoked) { - revokeUriPermissions(targetPkg, targetUserId, uri); + grantUriPermissions(uri, targetPkg, targetUserId, permissionOwner); } } - private boolean grantUriPermissions(@NonNull String targetPkg, @UserIdInt int targetUserId, - @NonNull Uri uri) { + private void grantUriPermissions(@NonNull Uri uri, @NonNull String targetPkg, + @UserIdInt int targetUserId, @NonNull IBinder permissionOwner) { final int sourceUserId = ContentProvider.getUserIdFromUri(uri, mSourceUserId); if (sVerbose) { Slog.v(TAG, "Granting URI permissions: uri=" + uri + ", sourceUid=" + mSourceUid + ", sourceUserId=" + sourceUserId - + ", targetPkg=" + targetPkg + ", targetUserId=" + targetUserId); + + ", targetPkg=" + targetPkg + ", targetUserId=" + targetUserId + + ", permissionOwner=" + toHexString(permissionOwner.hashCode())); } final Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(uri); final long ident = Binder.clearCallingIdentity(); try { mUgm.grantUriPermissionFromOwner( - mPermissionOwner, + permissionOwner, mSourceUid, targetPkg, uriWithoutUserId, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, targetUserId); - return true; } catch (RemoteException e) { Slog.e(TAG, "Granting URI permissions failed: uri=" + uri + ", sourceUid=" + mSourceUid + ", sourceUserId=" + sourceUserId - + ", targetPkg=" + targetPkg + ", targetUserId=" + targetUserId, e); - return false; - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - private void revokeUriPermissions(@NonNull String targetPkg, @UserIdInt int targetUserId, - @NonNull Uri uri) { - final int sourceUserId = ContentProvider.getUserIdFromUri(uri, mSourceUserId); - if (sVerbose) { - Slog.v(TAG, "Revoking URI permissions: uri=" + uri - + ", sourceUid=" + mSourceUid + ", sourceUserId=" + sourceUserId - + ", target=" + targetPkg + ", targetUserId=" + targetUserId); - } - final Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(uri); - final long ident = Binder.clearCallingIdentity(); - try { - mUgmInternal.revokeUriPermissionFromOwner( - mPermissionOwner, - uriWithoutUserId, - Intent.FLAG_GRANT_READ_URI_PERMISSION, - sourceUserId, - targetPkg, - targetUserId); + + ", targetPkg=" + targetPkg + ", targetUserId=" + targetUserId + + ", permissionOwner=" + toHexString(permissionOwner.hashCode()), e); } finally { Binder.restoreCallingIdentity(ident); } } - - private void addToActiveGrants(@NonNull Uri uri, @NonNull ComponentName targetActivity) { - synchronized (mLock) { - String packageName = targetActivity.getPackageName(); - List<Pair<Uri, String>> uris = mActiveGrantsByPackage.computeIfAbsent(packageName, - k -> new ArrayList<>(1)); - uris.add(Pair.create(uri, targetActivity.getClassName())); - } - } - - private Set<Uri> removeFromActiveGrants(@NonNull ComponentName targetActivity) { - synchronized (mLock) { - String targetPackageName = targetActivity.getPackageName(); - List<Pair<Uri, String>> uris = mActiveGrantsByPackage.get(targetPackageName); - if (uris == null || uris.isEmpty()) { - return Collections.emptySet(); - } - - // Collect all URIs whose grant was triggered by the target activity. - String targetActivityClassName = targetActivity.getClassName(); - Set<Uri> urisWhoseGrantsShouldBeRevoked = new ArraySet<>(1); - for (Iterator<Pair<Uri, String>> iter = uris.iterator(); iter.hasNext(); ) { - Pair<Uri, String> uriAndActivity = iter.next(); - if (uriAndActivity.second.equals(targetActivityClassName)) { - urisWhoseGrantsShouldBeRevoked.add(uriAndActivity.first); - iter.remove(); - } - } - - // A URI grant may have been triggered by more than one activity for the same package. - // We should not revoke a grant if it was triggered by multiple activities and one or - // more of those activities is still alive. Therefore we do a second pass and prune - // the set of URIs to be revoked if an additional activity that triggered its grant - // is still present. - for (Pair<Uri, String> uriAndActivity : uris) { - urisWhoseGrantsShouldBeRevoked.remove(uriAndActivity.first); - } - - // If there are no remaining URIs granted to the package, drop the entry from the map. - if (uris.isEmpty()) { - mActiveGrantsByPackage.remove(targetPackageName); - } - return urisWhoseGrantsShouldBeRevoked; - } - } - - /** - * Dump the active URI grants. - */ - public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { - synchronized (mLock) { - if (mActiveGrantsByPackage.isEmpty()) { - pw.print(prefix); pw.println("URI grants: none"); - return; - } - pw.print(prefix); pw.println("URI grants:"); - final String prefix2 = prefix + " "; - final String prefix3 = prefix2 + " "; - for (int i = mActiveGrantsByPackage.size() - 1; i >= 0; i--) { - String packageName = mActiveGrantsByPackage.keyAt(i); - pw.print(prefix2); pw.println(packageName); - List<Pair<Uri, String>> uris = mActiveGrantsByPackage.valueAt(i); - if (uris == null || uris.isEmpty()) { - continue; - } - for (Pair<Uri, String> uriAndActivity : uris) { - pw.print(prefix3); - pw.println(uriAndActivity.first + ": " + uriAndActivity.second); - } - } - } - } } diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java index db5bc4d5d4b0..8525e3634e3a 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java @@ -57,7 +57,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.IResultReceiver; import com.android.server.autofill.ui.InlineFillUi; -import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CancellationException; @@ -152,8 +151,8 @@ final class RemoteAugmentedAutofillService * Called by {@link Session} to request augmented autofill. */ public void onRequestAutofillLocked(int sessionId, @NonNull IAutoFillManagerClient client, - int taskId, @NonNull ComponentName activityComponent, @NonNull AutofillId focusedId, - @Nullable AutofillValue focusedValue, + int taskId, @NonNull ComponentName activityComponent, @NonNull IBinder activityToken, + @NonNull AutofillId focusedId, @Nullable AutofillValue focusedValue, @Nullable InlineSuggestionsRequest inlineSuggestionsRequest, @Nullable Function<InlineFillUi, Boolean> inlineSuggestionsCallback, @NonNull Runnable onErrorCallback, @@ -181,7 +180,8 @@ final class RemoteAugmentedAutofillService inlineSuggestionsRequest, inlineSuggestionsData, clientState, focusedId, focusedValue, inlineSuggestionsCallback, client, onErrorCallback, - remoteRenderService, userId, activityComponent); + remoteRenderService, userId, + activityComponent, activityToken); if (!showingFillWindow) { requestAutofill.complete(null); } @@ -253,7 +253,7 @@ final class RemoteAugmentedAutofillService @NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback, @Nullable RemoteInlineSuggestionRenderService remoteRenderService, int userId, - @NonNull ComponentName targetActivity) { + @NonNull ComponentName targetActivity, @NonNull IBinder targetActivityToken) { if (inlineSuggestionsData == null || inlineSuggestionsData.isEmpty() || inlineSuggestionsCallback == null || request == null || remoteRenderService == null) { @@ -307,8 +307,8 @@ final class RemoteAugmentedAutofillService final ArrayList<AutofillId> fieldIds = dataset.getFieldIds(); final ClipData content = dataset.getFieldContent(); if (content != null) { - mUriGrantsManager.grantUriPermissions( - targetActivity, userId, content); + mUriGrantsManager.grantUriPermissions(targetActivity, + targetActivityToken, userId, content); final AutofillId fieldId = fieldIds.get(0); if (sDebug) { Slog.d(TAG, "Calling client autofillContent(): " @@ -368,12 +368,6 @@ final class RemoteAugmentedAutofillService + ComponentName.flattenToShortString(mComponentName) + "]"; } - @Override - public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { - super.dump(prefix, pw); - mUriGrantsManager.dump(prefix, pw); - } - /** * Called by {@link Session} when it's time to destroy all augmented autofill requests. */ diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 57e5bb2d521f..042631d05186 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -450,7 +450,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } mPendingInlineSuggestionsRequest = inlineSuggestionsRequest; - maybeRequestFillLocked(); + maybeRequestFillFromServiceLocked(); viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST); } } : null; @@ -462,7 +462,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mPendingInlineSuggestionsRequest = inlineRequest; } - void maybeRequestFillLocked() { + void maybeRequestFillFromServiceLocked() { if (mPendingFillRequest == null) { return; } @@ -472,9 +472,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } - mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(), - mPendingFillRequest.getFillContexts(), mPendingFillRequest.getClientState(), - mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest); + if (mPendingInlineSuggestionsRequest.isServiceSupported()) { + mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(), + mPendingFillRequest.getFillContexts(), + mPendingFillRequest.getClientState(), + mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest); + } } mRemoteFillService.onFillRequest(mPendingFillRequest); @@ -581,7 +584,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState /*inlineSuggestionsRequest=*/null); mPendingFillRequest = request; - maybeRequestFillLocked(); + maybeRequestFillFromServiceLocked(); } if (mActivityToken != null) { @@ -1686,7 +1689,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (content != null) { final AutofillUriGrantsManager autofillUgm = remoteAugmentedAutofillService.getAutofillUriGrantsManager(); - autofillUgm.grantUriPermissions(mComponentName, userId, content); + autofillUgm.grantUriPermissions(mComponentName, mActivityToken, userId, content); } // Fill the value into the field. @@ -3188,6 +3191,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return false; } + final InlineSuggestionsRequest request = inlineSuggestionsRequest.get(); + if (mSessionFlags.mClientSuggestionsEnabled && !request.isClientSupported() + || !mSessionFlags.mClientSuggestionsEnabled && !request.isServiceSupported()) { + if (sDebug) { + Slog.d(TAG, "Inline suggestions not supported for " + + (mSessionFlags.mClientSuggestionsEnabled ? "client" : "service") + + ". Falling back to dropdown."); + } + return false; + } + final RemoteInlineSuggestionRenderService remoteRenderService = mService.getRemoteInlineSuggestionRenderServiceLocked(); if (remoteRenderService == null) { @@ -3196,7 +3210,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } final InlineFillUi.InlineFillUiInfo inlineFillUiInfo = - new InlineFillUi.InlineFillUiInfo(inlineSuggestionsRequest.get(), focusedId, + new InlineFillUi.InlineFillUiInfo(request, focusedId, filterText, remoteRenderService, userId, id); InlineFillUi inlineFillUi = InlineFillUi.forAutofill(inlineFillUiInfo, response, new InlineFillUi.InlineSuggestionUiCallback() { @@ -3523,7 +3537,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState synchronized (mLock) { logAugmentedAutofillRequestLocked(mode, remoteService.getComponentName(), focusedId, isWhitelisted, inlineSuggestionsRequest != null); - remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, + remoteService.onRequestAutofillLocked(id, mClient, + taskId, mComponentName, mActivityToken, AutofillId.withoutSession(focusedId), currentValue, inlineSuggestionsRequest, inlineSuggestionsResponseCallback, /*onErrorCallback=*/ () -> { @@ -3809,6 +3824,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mContexts = new ArrayList<>(1); } + if (inlineSuggestionsRequest != null && !inlineSuggestionsRequest.isClientSupported()) { + inlineSuggestionsRequest = null; + } + mClientSuggestionsSession.onFillRequest(requestId, inlineSuggestionsRequest, mFlags); } @@ -4149,13 +4168,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (remoteRenderService != null) { remoteRenderService.destroySuggestionViews(userId, id); } - final RemoteAugmentedAutofillService remoteAugmentedAutofillService = - mService.getRemoteAugmentedAutofillServiceIfCreatedLocked(); - if (remoteAugmentedAutofillService != null) { - final AutofillUriGrantsManager autofillUgm = - remoteAugmentedAutofillService.getAutofillUriGrantsManager(); - autofillUgm.revokeUriPermissions(mComponentName, userId); - } mDestroyed = true; diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index 78610a2857bd..0bd331b737c6 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -19,6 +19,15 @@ package com.android.server; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; +import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_COLLECT_LATENCY_DATA_KEY; +import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_DETAILED_TRACKING_KEY; +import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_ENABLED_KEY; +import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_IGNORE_BATTERY_STATUS_KEY; +import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_MAX_CALL_STATS_KEY; +import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_SAMPLING_INTERVAL_KEY; +import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_TRACK_DIRECT_CALLING_UID_KEY; +import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY; + import android.app.ActivityThread; import android.content.Context; import android.content.pm.PackageInfo; @@ -43,7 +52,6 @@ import com.android.internal.os.AppIdToPackageMap; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderInternal; -import com.android.internal.os.BinderLatencyObserver; import com.android.internal.os.CachedDeviceState; import com.android.internal.util.DumpUtils; @@ -125,28 +133,6 @@ public class BinderCallsStatsService extends Binder { /** Listens for flag changes. */ private static class SettingsObserver extends ContentObserver { - // Settings for BinderCallsStats. - private static final String SETTINGS_ENABLED_KEY = "enabled"; - private static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking"; - private static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data"; - private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; - private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state"; - private static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid"; - private static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count"; - private static final String SETTINGS_IGNORE_BATTERY_STATUS_KEY = "ignore_battery_status"; - // Settings for BinderLatencyObserver. - private static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_Latency_data"; - private static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY = - "latency_observer_sampling_interval"; - private static final String SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY = - "latency_observer_push_interval_minutes"; - private static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY = - "latency_histogram_bucket_count"; - private static final String SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY = - "latency_histogram_first_bucket_size"; - private static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY = - "latency_histogram_bucket_scale_factor"; - private boolean mEnabled; private final Uri mUri = Settings.Global.getUriFor(Settings.Global.BINDER_CALLS_STATS); private final Context mContext; @@ -206,23 +192,9 @@ public class BinderCallsStatsService extends Binder { mParser.getBoolean(SETTINGS_COLLECT_LATENCY_DATA_KEY, BinderCallsStats.DEFAULT_COLLECT_LATENCY_DATA)); // Binder latency observer settings. - BinderLatencyObserver binderLatencyObserver = mBinderCallsStats.getLatencyObserver(); - binderLatencyObserver.setSamplingInterval(mParser.getInt( - SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY, - BinderLatencyObserver.PERIODIC_SAMPLING_INTERVAL_DEFAULT)); - binderLatencyObserver.setHistogramBucketsParams( - mParser.getInt( - SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY, - BinderLatencyObserver.BUCKET_COUNT_DEFAULT), - mParser.getInt( - SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY, - BinderLatencyObserver.FIRST_BUCKET_SIZE_DEFAULT), - mParser.getFloat( - SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY, - BinderLatencyObserver.BUCKET_SCALE_FACTOR_DEFAULT)); - binderLatencyObserver.setPushInterval(mParser.getInt( - SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY, - BinderLatencyObserver.STATSD_PUSH_INTERVAL_MINUTES_DEFAULT)); + BinderCallsStats.SettingsObserver.configureLatencyObserver( + mParser, + mBinderCallsStats.getLatencyObserver()); final boolean enabled = mParser.getBoolean(SETTINGS_ENABLED_KEY, BinderCallsStats.ENABLED_DEFAULT); diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index c5246c7073ee..85ff2be43be4 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -312,19 +312,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, "Need BLUETOOTH_PRIVILEGED permission"); - final long token = Binder.clearCallingIdentity(); - try { - return onFactoryResetInternal(attributionSource); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - private boolean onFactoryResetInternal(AttributionSource attributionSource) { // Wait for stable state if bluetooth is temporary state. int state = getState(); if (state == BluetoothAdapter.STATE_BLE_TURNING_ON @@ -347,7 +334,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { addActiveLog( BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET, mContext.getPackageName(), false); - mBluetooth.onBrEdrDown(); + mBluetooth.onBrEdrDown(attributionSource); return true; } else if (state == BluetoothAdapter.STATE_ON) { addActiveLog( @@ -404,7 +391,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { addActiveLog( BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE, mContext.getPackageName(), false); - mBluetooth.onBrEdrDown(); + mBluetooth.onBrEdrDown(mContext.getAttributionSource()); mEnable = false; mEnableExternal = false; } @@ -888,7 +875,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (mBluetooth != null) { addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, mContext.getPackageName(), false); - mBluetooth.onBrEdrDown(); + mBluetooth.onBrEdrDown(mContext.getAttributionSource()); } } catch (RemoteException e) { Slog.e(TAG, "error when disabling bluetooth", e); @@ -1037,7 +1024,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (!mEnableExternal) { addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName, false); - sendBrEdrDownCallback(); + sendBrEdrDownCallback(attributionSource); } } return true; @@ -1074,12 +1061,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (!mEnableExternal && !isBleAppPresent()) { Slog.i(TAG, "Bluetooth was disabled while enabling BLE, disable BLE now"); mEnable = false; - mBluetooth.onBrEdrDown(); + mBluetooth.onBrEdrDown(mContext.getAttributionSource()); return; } if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) { // This triggers transition to STATE_ON - mBluetooth.onLeServiceUp(); + mBluetooth.onLeServiceUp(mContext.getAttributionSource()); persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); } } catch (RemoteException e) { @@ -1097,7 +1084,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, }) - private void sendBrEdrDownCallback() { + private void sendBrEdrDownCallback(AttributionSource attributionSource) { if (DBG) { Slog.d(TAG, "Calling sendBrEdrDownCallback callbacks"); } @@ -1110,7 +1097,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (isBleAppPresent()) { // Need to stay at BLE ON. Disconnect all Gatt connections try { - mBluetoothGatt.unregAll(mContext.getAttributionSource()); + mBluetoothGatt.unregAll(attributionSource); } catch (RemoteException e) { Slog.e(TAG, "Unable to disconnect all apps.", e); } @@ -1118,7 +1105,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { try { mBluetoothLock.readLock().lock(); if (mBluetooth != null) { - mBluetooth.onBrEdrDown(); + mBluetooth.onBrEdrDown(attributionSource); } } catch (RemoteException e) { Slog.e(TAG, "Call to onBrEdrDown() failed.", e); @@ -1319,7 +1306,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (mBluetooth != null) { //Unregister callback object try { - mBluetooth.unregisterCallback(mBluetoothCallback); + mBluetooth.unregisterCallback(mBluetoothCallback, + mContext.getAttributionSource()); } catch (RemoteException re) { Slog.e(TAG, "Unable to unregister BluetoothCallback", re); } @@ -1729,7 +1717,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { try { mBluetoothLock.readLock().lock(); if (mBluetooth != null) { - return mBluetooth.getAddressWithAttribution(mContext.getAttributionSource()); + return mBluetooth.getAddressWithAttribution(attributionSource); } } catch (RemoteException e) { Slog.e(TAG, @@ -1758,7 +1746,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { try { mBluetoothLock.readLock().lock(); if (mBluetooth != null) { - return mBluetooth.getName(mContext.getAttributionSource()); + return mBluetooth.getName(attributionSource); } } catch (RemoteException e) { Slog.e(TAG, "getName(): Unable to retrieve name remotely. Returning cached name", e); @@ -1886,7 +1874,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { int state = mBluetooth.getState(); if (state == BluetoothAdapter.STATE_BLE_ON) { Slog.w(TAG, "BT Enable in BLE_ON State, going to ON"); - mBluetooth.onLeServiceUp(); + mBluetooth.onLeServiceUp(mContext.getAttributionSource()); persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); break; } @@ -2105,7 +2093,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { //Register callback object try { - mBluetooth.registerCallback(mBluetoothCallback); + mBluetooth.registerCallback(mBluetoothCallback, + mContext.getAttributionSource()); } catch (RemoteException re) { Slog.e(TAG, "Unable to register BluetoothCallback", re); } @@ -2342,7 +2331,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { try { mBluetoothLock.readLock().lock(); if (mBluetooth != null) { - mBluetooth.unregisterCallback(mBluetoothCallback); + mBluetooth.unregisterCallback(mBluetoothCallback, + mContext.getAttributionSource()); } } catch (RemoteException re) { Slog.e(TAG, "Unable to unregister", re); @@ -2569,7 +2559,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { sendBluetoothStateCallback(false); // BT is OFF for general users // Broadcast as STATE_OFF newState = BluetoothAdapter.STATE_OFF; - sendBrEdrDownCallback(); + sendBrEdrDownCallback(mContext.getAttributionSource()); } } else if (newState == BluetoothAdapter.STATE_ON) { boolean isUp = (newState == BluetoothAdapter.STATE_ON); @@ -2670,7 +2660,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mBluetoothLock.readLock().lock(); if (mBluetooth != null) { //Unregister callback object - mBluetooth.unregisterCallback(mBluetoothCallback); + mBluetooth.unregisterCallback(mBluetoothCallback, mContext.getAttributionSource()); } } catch (RemoteException re) { Slog.e(TAG, "Unable to unregister", re); @@ -2890,6 +2880,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } } + @SuppressLint("AndroidFrameworkRequiresPermission") private static boolean checkPermissionForDataDelivery(Context context, String permission, AttributionSource attributionSource, String message) { final int result = PermissionChecker.checkPermissionForDataDeliveryFromDataSource( @@ -2916,6 +2907,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * * <p>Should be used in situations where the app op should not be noted. */ + @SuppressLint("AndroidFrameworkRequiresPermission") @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static boolean checkConnectPermissionForDataDelivery( Context context, AttributionSource attributionSource, String message) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index bfe51c2521df..8e12cb207232 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -15,6 +15,7 @@ */ package com.android.server; + import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.content.pm.PackageManager.FEATURE_BLUETOOTH; import static android.content.pm.PackageManager.FEATURE_WATCH; @@ -33,7 +34,6 @@ import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK; import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN; import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; @@ -53,6 +53,7 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS; import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL; import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID; @@ -8672,8 +8673,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // restore private DNS settings to default mode (opportunistic) if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) { - Settings.Global.putString(mContext.getContentResolver(), - ConnectivitySettingsManager.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC); + ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_OPPORTUNISTIC); } Settings.Global.putString(mContext.getContentResolver(), diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java index cd3dca90b39b..0f73897d2531 100644 --- a/services/core/java/com/android/server/SensorPrivacyService.java +++ b/services/core/java/com/android/server/SensorPrivacyService.java @@ -203,7 +203,7 @@ public final class SensorPrivacyService extends SystemService { SparseBooleanArray userIndividualEnabled = mIndividualEnabled.valueAt(i); for (int j = 0; j < userIndividualEnabled.size(); j++) { - int sensor = userIndividualEnabled.keyAt(i); + int sensor = userIndividualEnabled.keyAt(j); boolean enabled = userIndividualEnabled.valueAt(j); setUserRestriction(userId, sensor, enabled); } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index c7994c36d7d8..206f135aef99 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -70,6 +70,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE_E import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UptimeMillisLong; @@ -3078,6 +3079,18 @@ public final class ActiveServices { + ", uid=" + callingUid + " requires " + r.permission); return new ServiceLookupResult(null, r.permission); + } else if (Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(r.permission) + && callingUid != Process.SYSTEM_UID) { + // Hotword detection must run in its own sandbox, and we don't even trust + // its enclosing application to bind to it - only the system. + // TODO(b/185746653) remove this special case and generalize + Slog.w(TAG, "Permission Denial: Accessing service " + r.shortInstanceName + + " from pid=" + callingPid + + ", uid=" + callingUid + + " requiring permission " + r.permission + + " can only be bound to from the system."); + return new ServiceLookupResult(null, "can only be bound to " + + "by the system."); } else if (r.permission != null && callingPackage != null) { final int opCode = AppOpsManager.permissionToOpCode(r.permission); if (opCode != AppOpsManager.OP_NONE && mAm.getAppOpsManager().checkOpNoThrow( @@ -5920,6 +5933,10 @@ public final class ActiveServices { * @param durationMs Only meaningful for EXIT event, the duration from ENTER and EXIT state. */ private void logForegroundServiceStateChanged(ServiceRecord r, int state, int durationMs) { + if (!ActivityManagerUtils.shouldSamplePackageForAtom( + r.packageName, mAm.mConstants.mDefaultFgsAtomSampleRate)) { + return; + } FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortInstanceName, diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index c8363dd59005..bf574521b895 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -97,6 +97,7 @@ final class ActivityManagerConstants extends ContentObserver { static final String KEY_BOOT_TIME_TEMP_ALLOWLIST_DURATION = "boot_time_temp_allowlist_duration"; static final String KEY_FG_TO_BG_FGS_GRACE_DURATION = "fg_to_bg_fgs_grace_duration"; static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout"; + static final String KEY_FGS_ATOM_SAMPLE_RATE = "fgs_atom_sample_rate"; private static final int DEFAULT_MAX_CACHED_PROCESSES = 32; private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000; @@ -137,6 +138,7 @@ final class ActivityManagerConstants extends ContentObserver { private static final int DEFAULT_BOOT_TIME_TEMP_ALLOWLIST_DURATION = 10 * 1000; private static final long DEFAULT_FG_TO_BG_FGS_GRACE_DURATION = 5 * 1000; private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000; + private static final float DEFAULT_FGS_ATOM_SAMPLE_RATE = 1; // 100 % // Flag stored in the DeviceConfig API. /** @@ -430,6 +432,13 @@ final class ActivityManagerConstants extends ContentObserver { */ volatile long mFgsStartForegroundTimeoutMs = DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS; + /** + * Sample rate for the FGS westworld atom. + * + * If the value is 0.1, 10% of the installed packages would be sampled. + */ + volatile float mDefaultFgsAtomSampleRate = DEFAULT_FGS_ATOM_SAMPLE_RATE; + private final ActivityManagerService mService; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -629,6 +638,9 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_FGS_START_FOREGROUND_TIMEOUT: updateFgsStartForegroundTimeout(); break; + case KEY_FGS_ATOM_SAMPLE_RATE: + updateFgsAtomSamplePercent(); + break; default: break; } @@ -933,6 +945,13 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS); } + private void updateFgsAtomSamplePercent() { + mDefaultFgsAtomSampleRate = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_FGS_ATOM_SAMPLE_RATE, + DEFAULT_FGS_ATOM_SAMPLE_RATE); + } + private void updateImperceptibleKillExemptions() { IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.clear(); IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.addAll(mDefaultImperceptibleKillExemptPackages); @@ -1145,6 +1164,8 @@ final class ActivityManagerConstants extends ContentObserver { pw.println(mFlagFgsStartRestrictionEnabled); pw.print(" "); pw.print(KEY_DEFAULT_FGS_STARTS_RESTRICTION_CHECK_CALLER_TARGET_SDK); pw.print("="); pw.println(mFgsStartRestrictionCheckCallerTargetSdk); + pw.print(" "); pw.print(KEY_FGS_ATOM_SAMPLE_RATE); + pw.print("="); pw.println(mDefaultFgsAtomSampleRate); pw.println(); if (mOverrideMaxCachedProcesses >= 0) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9568fa512cf5..00b13b1bb6b0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7775,7 +7775,17 @@ public class ActivityManagerService extends IActivityManager.Stub : ServerProtoEnums.ERROR_SOURCE_UNKNOWN, incrementalMetrics != null /* isIncremental */, loadingProgress, incrementalMetrics != null ? incrementalMetrics.getMillisSinceOldestPendingRead() - : -1 + : -1, + 0 /* storage_health_code */, + 0 /* data_loader_status_code */, + false /* read_logs_enabled */, + 0 /* millis_since_last_data_loader_bind */, + 0 /* data_loader_bind_delay_millis */, + 0 /* total_delayed_reads */, + 0 /* total_failed_reads */, + 0 /* last_read_error_uid */, + 0 /* last_read_error_millis_since */, + 0 /* last_read_error_code */ ); final int relaunchReason = r == null ? RELAUNCH_REASON_NONE diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 6fa8ecd41d7c..f2762fc965ee 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -3382,7 +3382,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" Sets the inactive state of an app."); pw.println(" get-inactive [--user <USER_ID>] <PACKAGE>"); pw.println(" Returns the inactive state of an app."); - pw.println(" set-standby-bucket [--user <USER_ID>] <PACKAGE> active|working_set|frequent|rare"); + pw.println(" set-standby-bucket [--user <USER_ID>] <PACKAGE> active|working_set|frequent|rare|restricted"); pw.println(" Puts an app in the standby bucket."); pw.println(" get-standby-bucket [--user <USER_ID>] <PACKAGE>"); pw.println(" Returns the standby bucket of an app."); diff --git a/services/core/java/com/android/server/am/ActivityManagerUtils.java b/services/core/java/com/android/server/am/ActivityManagerUtils.java new file mode 100644 index 000000000000..dd2414866542 --- /dev/null +++ b/services/core/java/com/android/server/am/ActivityManagerUtils.java @@ -0,0 +1,124 @@ +/* + * 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.am; + +import android.app.ActivityThread; +import android.provider.Settings; +import android.util.ArrayMap; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * To store random utility methods... + */ +public class ActivityManagerUtils { + private ActivityManagerUtils() { + } + + private static Integer sAndroidIdHash; + + @GuardedBy("sHashCache") + private static final ArrayMap<String, Integer> sHashCache = new ArrayMap<>(); + + private static String sInjectedAndroidId; + + /** Used by the unit tests to inject an android ID. Do not set in the prod code. */ + @VisibleForTesting + static void injectAndroidIdForTest(String androidId) { + sInjectedAndroidId = androidId; + sAndroidIdHash = null; + } + + /** + * Return a hash between [0, MAX_VALUE] generated from the android ID. + */ + @VisibleForTesting + static int getAndroidIdHash() { + // No synchronization is required. Double-initialization is fine here. + if (sAndroidIdHash == null) { + final String androidId = Settings.Secure.getString( + ActivityThread.currentApplication().getContentResolver(), + Settings.Secure.ANDROID_ID); + sAndroidIdHash = getUnsignedHashUnCached( + sInjectedAndroidId != null ? sInjectedAndroidId : androidId); + } + return sAndroidIdHash; + } + + /** + * Return a hash between [0, MAX_VALUE] generated from a package name, using a cache. + * + * Because all the results are cached, do not use it for dynamically generated strings. + */ + @VisibleForTesting + static int getUnsignedHashCached(String s) { + synchronized (sHashCache) { + final Integer cached = sHashCache.get(s); + if (cached != null) { + return cached; + } + final int hash = getUnsignedHashUnCached(s); + sHashCache.put(s.intern(), hash); + return hash; + } + } + + /** + * Return a hash between [0, MAX_VALUE] generated from a package name. + */ + private static int getUnsignedHashUnCached(String s) { + try { + final MessageDigest digest = MessageDigest.getInstance("SHA-1"); + digest.update(s.getBytes()); + return unsignedIntFromBytes(digest.digest()); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + @VisibleForTesting + static int unsignedIntFromBytes(byte[] longEnoughBytes) { + return (extractByte(longEnoughBytes, 0) + | extractByte(longEnoughBytes, 1) + | extractByte(longEnoughBytes, 2) + | extractByte(longEnoughBytes, 3)) + & 0x7FFF_FFFF; + } + + private static int extractByte(byte[] bytes, int index) { + return (((int) bytes[index]) & 0xFF) << (index * 8); + } + + /** + * @return whether a package should be logged, using a random value based on the ANDROID_ID, + * with a given sampling rate. + */ + public static boolean shouldSamplePackageForAtom(String packageName, float rate) { + if (rate <= 0) { + return false; + } + if (rate >= 1) { + return true; + } + final int hash = getUnsignedHashCached(packageName) ^ getAndroidIdHash(); + + return (((double) hash) / Integer.MAX_VALUE) <= rate; + } +} diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index 859cc441daa1..406e8665735d 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -663,7 +663,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { final long gnssChargeUC = measuredEnergyDeltas.gnssChargeUC; if (gnssChargeUC != MeasuredEnergySnapshot.UNAVAILABLE) { - mStats.updateGnssMeasuredEnergyStatsLocked(displayChargeUC, elapsedRealtime); + mStats.updateGnssMeasuredEnergyStatsLocked(gnssChargeUC, elapsedRealtime); } } // Inform mStats about each applicable custom energy bucket. diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 8dc9d03dedb7..cc750ce3eefe 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -395,7 +395,7 @@ public final class CachedAppOptimizer { pw.println(" Tracking last compaction stats for " + mLastCompactionStats.size() + " processes."); - pw.println(" " + KEY_USE_FREEZER + "=" + mUseFreezer); + pw.println(" " + KEY_USE_FREEZER + "=" + mUseFreezer); pw.println(" " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate); pw.println(" " + KEY_FREEZER_DEBOUNCE_TIMEOUT + "=" + mFreezerDebounceTimeout); if (DEBUG_COMPACTION) { diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 61c92b701346..649d05036027 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -3035,6 +3035,10 @@ public final class OomAdjuster { return; } + if (app.mOptRecord.isFreezeExempt()) { + return; + } + final ProcessCachedOptimizerRecord opt = app.mOptRecord; // if an app is already frozen and shouldNotFreeze becomes true, immediately unfreeze if (opt.isFrozen() && opt.shouldNotFreeze()) { diff --git a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java index 026c1d3fd204..a33e7e5bac37 100644 --- a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java +++ b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java @@ -80,6 +80,12 @@ final class ProcessCachedOptimizerRecord { @GuardedBy("mProcLock") private boolean mShouldNotFreeze; + /** + * Exempt from freezer (now for system apps with INSTALL_PACKAGES permission) + */ + @GuardedBy("mProcLock") + private boolean mFreezeExempt; + @GuardedBy("mProcLock") long getLastCompactTime() { return mLastCompactTime; @@ -160,6 +166,16 @@ final class ProcessCachedOptimizerRecord { mShouldNotFreeze = shouldNotFreeze; } + @GuardedBy("mProcLock") + boolean isFreezeExempt() { + return mFreezeExempt; + } + + @GuardedBy("mPreLock") + void setFreezeExempt(boolean exempt) { + mFreezeExempt = exempt; + } + ProcessCachedOptimizerRecord(ProcessRecord app) { mApp = app; mProcLock = app.mService.mProcLock; @@ -173,6 +189,7 @@ final class ProcessCachedOptimizerRecord { void dump(PrintWriter pw, String prefix, long nowUptime) { pw.print(prefix); pw.print("lastCompactTime="); pw.print(mLastCompactTime); pw.print(" lastCompactAction="); pw.println(mLastCompactAction); + pw.print(prefix); pw.print("isFreezeExempt="); pw.print(mFreezeExempt); pw.print(" " + IS_FROZEN + "="); pw.println(mFrozen); } } diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java index 6ff3bf652e3c..167ed864fbcd 100644 --- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java @@ -432,7 +432,17 @@ class ProcessErrorStateRecord { (mApp.info != null) ? mApp.info.packageName : "", incrementalMetrics != null /* isIncremental */, loadingProgress, incrementalMetrics != null ? incrementalMetrics.getMillisSinceOldestPendingRead() - : -1); + : -1, + 0 /* storage_health_code */, + 0 /* data_loader_status_code */, + false /* read_logs_enabled */, + 0 /* millis_since_last_data_loader_bind */, + 0 /* data_loader_bind_delay_millis */, + 0 /* total_delayed_reads */, + 0 /* total_failed_reads */, + 0 /* last_read_error_uid */, + 0 /* last_read_error_millis_since */, + 0 /* last_read_error_code */); final ProcessRecord parentPr = parentProcess != null ? (ProcessRecord) parentProcess.mOwner : null; mService.addErrorToDropBox("anr", mApp, mApp.processName, activityShortComponentName, diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index fae941d172a2..5a9c4dea4703 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -54,6 +54,7 @@ import static com.android.server.am.ActivityManagerService.TAG_NETWORK; import static com.android.server.am.ActivityManagerService.TAG_PROCESSES; import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS; +import android.Manifest; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityManager.ProcessCapability; @@ -76,6 +77,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.res.Resources; import android.graphics.Point; @@ -1774,8 +1776,8 @@ public final class ProcessList { checkSlow(startTime, "startProcess: done updating cpu stats"); try { + final int userId = UserHandle.getUserId(app.uid); try { - final int userId = UserHandle.getUserId(app.uid); AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); @@ -1798,6 +1800,12 @@ public final class ProcessList { app.info.packageName); externalStorageAccess = storageManagerInternal.hasExternalStorageAccess(uid, app.info.packageName); + if (pm.checkPermission(Manifest.permission.INSTALL_PACKAGES, + app.info.packageName, userId) + == PackageManager.PERMISSION_GRANTED) { + Slog.i(TAG, app.info.packageName + " is exempt from freezer"); + app.mOptRecord.setFreezeExempt(true); + } } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java index efb0f4a9343c..52388ff2877c 100644 --- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java +++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java @@ -33,6 +33,11 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.IActivityManager; +import android.app.StatsManager; +import android.app.StatsManager.StatsPullAtomCallback; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStatsManagerInternal; +import android.app.usage.UsageStatsManagerInternal.UsageEventListener; import android.apphibernation.IAppHibernationService; import android.content.BroadcastReceiver; import android.content.Context; @@ -43,6 +48,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.UserInfo; import android.os.Binder; import android.os.Environment; import android.os.RemoteException; @@ -59,10 +65,12 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; +import android.util.StatsEvent; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -148,8 +156,8 @@ public final class AppHibernationService extends SystemService { intentFilter.addAction(ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); userAllContext.registerReceiver(mBroadcastReceiver, intentFilter); - LocalServices.addService(AppHibernationManagerInternal.class, mLocalService); + mInjector.getUsageStatsManagerInternal().registerListener(mUsageEventListener); } @Override @@ -174,6 +182,12 @@ public final class AppHibernationService extends SystemService { NAMESPACE_APP_HIBERNATION, ActivityThread.currentApplication().getMainExecutor(), this::onDeviceConfigChanged); + getContext().getSystemService(StatsManager.class) + .setPullAtomCallback( + FrameworkStatsLog.USER_LEVEL_HIBERNATED_APPS, + /* metadata */ null, // use default PullAtomMetadata values + mBackgroundExecutor, + new StatsPullAtomCallbackImpl()); } } @@ -269,6 +283,16 @@ public final class AppHibernationService extends SystemService { } else { unhibernatePackageForUser(packageName, userId, pkgState); } + final UserLevelState stateSnapshot = new UserLevelState(pkgState); + final int userIdSnapshot = userId; + mBackgroundExecutor.execute(() -> { + FrameworkStatsLog.write( + FrameworkStatsLog.USER_LEVEL_HIBERNATION_STATE_CHANGED, + stateSnapshot.packageName, + userIdSnapshot, + stateSnapshot.hibernated, + stateSnapshot.lastUnhibernatedMs); + }); List<UserLevelState> states = new ArrayList<>(mUserStates.get(userId).values()); mUserDiskStores.get(userId).scheduleWriteHibernationStates(states); } @@ -785,6 +809,20 @@ public final class AppHibernationService extends SystemService { } }; + private final UsageEventListener mUsageEventListener = (userId, event) -> { + if (!isAppHibernationEnabled()) { + return; + } + final int eventType = event.mEventType; + if (eventType == UsageEvents.Event.USER_INTERACTION + || eventType == UsageEvents.Event.ACTIVITY_RESUMED + || eventType == UsageEvents.Event.APP_COMPONENT_USED) { + final String pkgName = event.mPackage; + setHibernatingForUser(pkgName, userId, false); + setHibernatingGlobally(pkgName, false); + } + }; + /** * Whether app hibernation is enabled on this device. * @@ -817,6 +855,8 @@ public final class AppHibernationService extends SystemService { Executor getBackgroundExecutor(); + UsageStatsManagerInternal getUsageStatsManagerInternal(); + HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore(); HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId); @@ -867,6 +907,11 @@ public final class AppHibernationService extends SystemService { } @Override + public UsageStatsManagerInternal getUsageStatsManagerInternal() { + return LocalServices.getService(UsageStatsManagerInternal.class); + } + + @Override public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() { File dir = new File(Environment.getDataSystemDirectory(), HIBERNATION_DIR_NAME); return new HibernationStateDiskStore<>( @@ -886,4 +931,29 @@ public final class AppHibernationService extends SystemService { com.android.internal.R.bool.config_hibernationDeletesOatArtifactsEnabled); } } + + private final class StatsPullAtomCallbackImpl implements StatsPullAtomCallback { + @Override + public int onPullAtom(int atomTag, @NonNull List<StatsEvent> data) { + if (atomTag != FrameworkStatsLog.USER_LEVEL_HIBERNATED_APPS) { + return StatsManager.PULL_SKIP; + } + if (isAppHibernationEnabled()) { + List<UserInfo> userInfos = mUserManager.getAliveUsers(); + final int numUsers = userInfos.size(); + for (int i = 0; i < numUsers; ++i) { + final int userId = userInfos.get(i).id; + if (mUserManager.isUserUnlockingOrUnlocked(userId)) { + data.add( + FrameworkStatsLog.buildStatsEvent( + atomTag, + getHibernatingPackagesForUser(userId).size(), + userId) + ); + } + } + } + return StatsManager.PULL_SUCCESS; + } + } } diff --git a/services/core/java/com/android/server/apphibernation/UserLevelState.java b/services/core/java/com/android/server/apphibernation/UserLevelState.java index b75b19d8df74..68c363c8256a 100644 --- a/services/core/java/com/android/server/apphibernation/UserLevelState.java +++ b/services/core/java/com/android/server/apphibernation/UserLevelState.java @@ -31,6 +31,14 @@ final class UserLevelState { @CurrentTimeMillisLong public long lastUnhibernatedMs; + UserLevelState() {} + + UserLevelState(UserLevelState state) { + packageName = state.packageName; + hibernated = state.hibernated; + lastUnhibernatedMs = state.lastUnhibernatedMs; + } + @Override public String toString() { return "UserLevelState{" diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java index f2e422d3ee7c..63b41b789280 100644 --- a/services/core/java/com/android/server/appop/DiscreteRegistry.java +++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java @@ -92,8 +92,8 @@ final class DiscreteRegistry { "discrete_history_quantization_millis"; private static final String PROPERTY_DISCRETE_FLAGS = "discrete_history_op_flags"; private static final String PROPERTY_DISCRETE_OPS_LIST = "discrete_history_ops_cslist"; - private static final String DEFAULT_DISCRETE_OPS = OP_CAMERA + "," + OP_RECORD_AUDIO + "," - + OP_FINE_LOCATION + "," + OP_COARSE_LOCATION; + private static final String DEFAULT_DISCRETE_OPS = OP_FINE_LOCATION + "," + OP_COARSE_LOCATION + + "," + OP_CAMERA + "," + OP_RECORD_AUDIO; private static final long DEFAULT_DISCRETE_HISTORY_CUTOFF = Duration.ofHours(24).toMillis(); private static final long MAXIMUM_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(30).toMillis(); private static final long DEFAULT_DISCRETE_HISTORY_QUANTIZATION = @@ -104,7 +104,6 @@ final class DiscreteRegistry { private static int[] sDiscreteOps; private static int sDiscreteFlags; - private static final String TAG_HISTORY = "h"; private static final String ATTR_VERSION = "v"; private static final int CURRENT_VERSION = 1; @@ -144,6 +143,8 @@ final class DiscreteRegistry { @GuardedBy("mOnDiskLock") private DiscreteOps mCachedOps = null; + private boolean mDebugMode = false; + DiscreteRegistry(Object inMemoryLock) { mInMemoryLock = inMemoryLock; } @@ -159,40 +160,35 @@ final class DiscreteRegistry { AsyncTask.THREAD_POOL_EXECUTOR, (DeviceConfig.Properties p) -> { setDiscreteHistoryParameters(p); }); - sDiscreteHistoryCutoff = DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_DISCRETE_HISTORY_CUTOFF, DEFAULT_DISCRETE_HISTORY_CUTOFF); - sDiscreteHistoryQuantization = DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_DISCRETE_HISTORY_QUANTIZATION, DEFAULT_DISCRETE_HISTORY_QUANTIZATION); - sDiscreteFlags = DeviceConfig.getInt(DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_DISCRETE_FLAGS, OP_FLAGS_DISCRETE); - sDiscreteOps = parseOpsList(DeviceConfig.getString(DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_DISCRETE_OPS_LIST, DEFAULT_DISCRETE_OPS)); + setDiscreteHistoryParameters(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_PRIVACY)); } private void setDiscreteHistoryParameters(DeviceConfig.Properties p) { if (p.getKeyset().contains(PROPERTY_DISCRETE_HISTORY_CUTOFF)) { sDiscreteHistoryCutoff = p.getLong(PROPERTY_DISCRETE_HISTORY_CUTOFF, DEFAULT_DISCRETE_HISTORY_CUTOFF); - if (!Build.IS_DEBUGGABLE) { + if (!Build.IS_DEBUGGABLE && !mDebugMode) { sDiscreteHistoryCutoff = min(MAXIMUM_DISCRETE_HISTORY_CUTOFF, sDiscreteHistoryCutoff); } + } else { + sDiscreteHistoryCutoff = DEFAULT_DISCRETE_HISTORY_CUTOFF; } if (p.getKeyset().contains(PROPERTY_DISCRETE_HISTORY_QUANTIZATION)) { sDiscreteHistoryQuantization = p.getLong(PROPERTY_DISCRETE_HISTORY_QUANTIZATION, DEFAULT_DISCRETE_HISTORY_QUANTIZATION); - if (!Build.IS_DEBUGGABLE) { + if (!Build.IS_DEBUGGABLE && !mDebugMode) { sDiscreteHistoryQuantization = max(DEFAULT_DISCRETE_HISTORY_QUANTIZATION, sDiscreteHistoryQuantization); } + } else { + sDiscreteHistoryQuantization = DEFAULT_DISCRETE_HISTORY_QUANTIZATION; } - if (p.getKeyset().contains(PROPERTY_DISCRETE_FLAGS)) { - sDiscreteFlags = p.getInt(PROPERTY_DISCRETE_FLAGS, OP_FLAGS_DISCRETE); - } - if (p.getKeyset().contains(PROPERTY_DISCRETE_OPS_LIST)) { - sDiscreteOps = parseOpsList(p.getString(PROPERTY_DISCRETE_OPS_LIST, - DEFAULT_DISCRETE_OPS)); - } + sDiscreteFlags = p.getKeyset().contains(PROPERTY_DISCRETE_FLAGS) ? sDiscreteFlags = + p.getInt(PROPERTY_DISCRETE_FLAGS, OP_FLAGS_DISCRETE) : OP_FLAGS_DISCRETE; + sDiscreteOps = p.getKeyset().contains(PROPERTY_DISCRETE_OPS_LIST) ? parseOpsList( + p.getString(PROPERTY_DISCRETE_OPS_LIST, DEFAULT_DISCRETE_OPS)) : parseOpsList( + DEFAULT_DISCRETE_OPS); } void recordDiscreteAccess(int uid, String packageName, int op, @Nullable String attributionTag, @@ -232,6 +228,8 @@ final class DiscreteRegistry { @Nullable String packageNameFilter, @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) { DiscreteOps discreteOps = getAllDiscreteOps(); + beginTimeMillis = max(beginTimeMillis, Instant.now().minus(sDiscreteHistoryCutoff, + ChronoUnit.MILLIS).toEpochMilli()); discreteOps.filter(beginTimeMillis, endTimeMillis, filter, uidFilter, packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter); discreteOps.applyToHistoricalOps(result); @@ -282,6 +280,18 @@ final class DiscreteRegistry { } } + void offsetHistory(long offset) { + synchronized (mOnDiskLock) { + DiscreteOps discreteOps; + synchronized (mInMemoryLock) { + discreteOps = getAllDiscreteOps(); + clearHistory(); + } + discreteOps.offsetHistory(offset); + persistDiscreteOpsLocked(discreteOps); + } + } + void dump(@NonNull PrintWriter pw, int uidFilter, @Nullable String packageNameFilter, @Nullable String attributionTagFilter, @AppOpsManager.HistoricalOpsRequestFilter int filter, int dumpOp, @@ -363,6 +373,13 @@ final class DiscreteRegistry { } } + private void offsetHistory(long offset) { + int nUids = mUids.size(); + for (int i = 0; i < nUids; i++) { + mUids.valueAt(i).offsetHistory(offset); + } + } + private void clearHistory(int uid, String packageName) { if (mUids.containsKey(uid)) { mUids.get(uid).clearPackage(packageName); @@ -549,6 +566,13 @@ final class DiscreteRegistry { } } + private void offsetHistory(long offset) { + int nPackages = mPackages.size(); + for (int i = 0; i < nPackages; i++) { + mPackages.valueAt(i).offsetHistory(offset); + } + } + private void clearPackage(String packageName) { mPackages.remove(packageName); } @@ -656,6 +680,13 @@ final class DiscreteRegistry { } } + private void offsetHistory(long offset) { + int nOps = mPackageOps.size(); + for (int i = 0; i < nOps; i++) { + mPackageOps.valueAt(i).offsetHistory(offset); + } + } + private DiscreteOp getOrCreateDiscreteOp(int op) { DiscreteOp result = mPackageOps.get(op); if (result == null) { @@ -749,12 +780,29 @@ final class DiscreteRegistry { } } + private void offsetHistory(long offset) { + int nTags = mAttributedOps.size(); + for (int i = 0; i < nTags; i++) { + List<DiscreteOpEvent> list = mAttributedOps.valueAt(i); + + int n = list.size(); + for (int j = 0; j < n; j++) { + DiscreteOpEvent event = list.get(j); + list.set(j, new DiscreteOpEvent(event.mNoteTime - offset, event.mNoteDuration, + event.mUidState, event.mOpFlag)); + } + } + } + void addDiscreteAccess(@Nullable String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) { List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList( attributionTag); accessTime = accessTime / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization; + accessDuration = accessDuration == -1 ? -1 + : (accessDuration + sDiscreteHistoryQuantization - 1) + / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization; int nAttributedOps = attributedOps.size(); int i = nAttributedOps; @@ -764,8 +812,7 @@ final class DiscreteRegistry { break; } if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) { - if (accessDuration != previousOp.mNoteDuration - && accessDuration > sDiscreteHistoryQuantization) { + if (accessDuration != previousOp.mNoteDuration) { break; } else { return; @@ -983,5 +1030,9 @@ final class DiscreteRegistry { } return true; } + + void setDebugMode(boolean debugMode) { + this.mDebugMode = debugMode; + } } diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index ffd24587618f..72e582e594b4 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -553,6 +553,11 @@ final class HistoricalRegistry { if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) { clearHistoryOnDiskDLocked(); } + if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE) { + mDiscreteRegistry.setDebugMode(true); + } else { + mDiscreteRegistry.setDebugMode(false); + } } if (mBaseSnapshotInterval != baseSnapshotInterval) { mBaseSnapshotInterval = baseSnapshotInterval; @@ -591,6 +596,7 @@ final class HistoricalRegistry { mPersistence.persistHistoricalOpsDLocked(history); } } + mDiscreteRegistry.offsetHistory(offsetMillis); } void addHistoricalOps(HistoricalOps ops) { diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java index 88e47a0efd83..6f73985fbcd4 100644 --- a/services/core/java/com/android/server/biometrics/AuthService.java +++ b/services/core/java/com/android/server/biometrics/AuthService.java @@ -30,12 +30,14 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS; import static android.hardware.biometrics.BiometricManager.Authenticators; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.biometrics.BiometricAuthenticator; +import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IAuthService; -import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceReceiver; @@ -44,7 +46,11 @@ import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.PromptInfo; import android.hardware.biometrics.SensorPropertiesInternal; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceService; +import android.hardware.fingerprint.FingerprintSensorProperties; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintService; import android.hardware.iris.IIrisService; import android.os.Binder; @@ -58,11 +64,10 @@ import android.util.Slog; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.server.SystemService; -import com.android.server.biometrics.sensors.face.FaceAuthenticator; -import com.android.server.biometrics.sensors.fingerprint.FingerprintAuthenticator; -import com.android.server.biometrics.sensors.iris.IrisAuthenticator; +import java.util.ArrayList; import java.util.List; /** @@ -337,7 +342,7 @@ public class AuthService extends SystemService { } @Override - public long[] getAuthenticatorIds() throws RemoteException { + public long[] getAuthenticatorIds(int userId) throws RemoteException { // In this method, we're not checking whether the caller is permitted to use face // API because current authenticator ID is leaked (in a more contrived way) via Android // Keystore (android.security.keystore package): the user of that API can create a key @@ -355,9 +360,13 @@ public class AuthService extends SystemService { // method from inside app processes. final int callingUserId = UserHandle.getCallingUserId(); + if (userId != callingUserId) { + getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL, + "Must have " + USE_BIOMETRIC_INTERNAL + " permission."); + } final long identity = Binder.clearCallingIdentity(); try { - return mBiometricService.getAuthenticatorIds(callingUserId); + return mBiometricService.getAuthenticatorIds(userId); } finally { Binder.restoreCallingIdentity(identity); } @@ -574,81 +583,119 @@ public class AuthService extends SystemService { mImpl = new AuthServiceImpl(); } + + /** + * Registration of all HIDL and AIDL biometric HALs starts here. + * The flow looks like this: + * AuthService + * └── .onStart() + * └── .registerAuthenticators(...) + * ├── FaceService.registerAuthenticators(...) + * │ └── for (p : serviceProviders) + * │ └── for (s : p.sensors) + * │ └── BiometricService.registerAuthenticator(s) + * │ + * ├── FingerprintService.registerAuthenticators(...) + * │ └── for (p : serviceProviders) + * │ └── for (s : p.sensors) + * │ └── BiometricService.registerAuthenticator(s) + * │ + * └── IrisService.registerAuthenticators(...) + * └── for (p : serviceProviders) + * └── for (s : p.sensors) + * └── BiometricService.registerAuthenticator(s) + */ @Override public void onStart() { mBiometricService = mInjector.getBiometricService(); + final SensorConfig[] hidlConfigs; if (!mInjector.isHidlDisabled(getContext())) { - final String[] configs = mInjector.getConfiguration(getContext()); - for (String config : configs) { - try { - registerAuthenticator(new SensorConfig(config)); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception", e); - } + final String[] configStrings = mInjector.getConfiguration(getContext()); + hidlConfigs = new SensorConfig[configStrings.length]; + for (int i = 0; i < configStrings.length; ++i) { + hidlConfigs[i] = new SensorConfig(configStrings[i]); } + } else { + hidlConfigs = null; } + // Registers HIDL and AIDL authenticators, but only HIDL configs need to be provided. + registerAuthenticators(hidlConfigs); + mInjector.publishBinderService(this, mImpl); } - private void registerAuthenticator(SensorConfig config) throws RemoteException { - Slog.d(TAG, "Registering ID: " + config.id - + " Modality: " + config.modality - + " Strength: " + config.strength); - - final IBiometricAuthenticator.Stub authenticator; + /** + * Registers HIDL and AIDL authenticators for all of the available modalities. + * + * @param hidlSensors Array of {@link SensorConfig} configuration for all of the HIDL sensors + * available on the device. This array may contain configuration for + * different modalities and different sensors of the same modality in + * arbitrary order. Can be null if no HIDL sensors exist on the device. + */ + private void registerAuthenticators(@Nullable SensorConfig[] hidlSensors) { + List<FingerprintSensorPropertiesInternal> hidlFingerprintSensors = new ArrayList<>(); + List<FaceSensorPropertiesInternal> hidlFaceSensors = new ArrayList<>(); + // Iris doesn't have IrisSensorPropertiesInternal, using SensorPropertiesInternal instead. + List<SensorPropertiesInternal> hidlIrisSensors = new ArrayList<>(); + + if (hidlSensors != null) { + for (SensorConfig sensor : hidlSensors) { + Slog.d(TAG, "Registering HIDL ID: " + sensor.id + " Modality: " + sensor.modality + + " Strength: " + sensor.strength); + switch (sensor.modality) { + case TYPE_FINGERPRINT: + hidlFingerprintSensors.add( + getHidlFingerprintSensorProps(sensor.id, sensor.strength)); + break; - switch (config.modality) { - case TYPE_FINGERPRINT: - final IFingerprintService fingerprintService = mInjector.getFingerprintService(); - if (fingerprintService == null) { - Slog.e(TAG, "Attempting to register with null FingerprintService." - + " Please check your device configuration."); - return; - } + case TYPE_FACE: + hidlFaceSensors.add(getHidlFaceSensorProps(sensor.id, sensor.strength)); + break; - // Initialize this outside of FingerprintAuthenticator. Only HIDL HALs require - // initialization from here. AIDL HALs are initialized by FingerprintService since - // the HAL interface provides ID, strength, and other configuration information. - fingerprintService.initializeConfiguration(config.id, config.strength); - authenticator = new FingerprintAuthenticator(fingerprintService, config.id); - break; - - case TYPE_FACE: - final IFaceService faceService = mInjector.getFaceService(); - if (faceService == null) { - Slog.e(TAG, "Attempting to register with null FaceService. Please check " - + " your device configuration."); - return; - } + case TYPE_IRIS: + hidlIrisSensors.add(getHidlIrisSensorProps(sensor.id, sensor.strength)); + break; - // Initialize this outside of FingerprintAuthenticator. Only HIDL HALs require - // initialization from here. AIDL HALs are initialized by FaceService since - // the HAL interface provides ID, strength, and other configuration information. - faceService.initializeConfiguration(config.id, config.strength); - authenticator = new FaceAuthenticator(faceService, config.id); - break; - - case TYPE_IRIS: - final IIrisService irisService = mInjector.getIrisService(); - if (irisService == null) { - Slog.e(TAG, "Attempting to register with null IrisService. Please check" - + " your device configuration."); - return; + default: + Slog.e(TAG, "Unknown modality: " + sensor.modality); } + } + } - irisService.initializeConfiguration(config.id, config.strength); - authenticator = new IrisAuthenticator(irisService, config.id); - break; + final IFingerprintService fingerprintService = mInjector.getFingerprintService(); + if (fingerprintService != null) { + try { + fingerprintService.registerAuthenticators(hidlFingerprintSensors); + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when registering fingerprint authenticators", e); + } + } else if (hidlFingerprintSensors.size() > 0) { + Slog.e(TAG, "HIDL fingerprint configuration exists, but FingerprintService is null."); + } - default: - Slog.e(TAG, "Unknown modality: " + config.modality); - return; + final IFaceService faceService = mInjector.getFaceService(); + if (faceService != null) { + try { + faceService.registerAuthenticators(hidlFaceSensors); + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when registering face authenticators", e); + } + } else if (hidlFaceSensors.size() > 0) { + Slog.e(TAG, "HIDL face configuration exists, but FaceService is null."); } - mBiometricService.registerAuthenticator(config.id, config.modality, config.strength, - authenticator); + final IIrisService irisService = mInjector.getIrisService(); + if (irisService != null) { + try { + irisService.registerAuthenticators(hidlIrisSensors); + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when registering iris authenticators", e); + } + } else if (hidlIrisSensors.size() > 0) { + Slog.e(TAG, "HIDL iris configuration exists, but IrisService is null."); + } } private void checkInternalPermission() { @@ -674,4 +721,72 @@ public class AuthService extends SystemService { return modality == BiometricAuthenticator.TYPE_CREDENTIAL ? modality : (modality & ~BiometricAuthenticator.TYPE_CREDENTIAL); } + + + private FingerprintSensorPropertiesInternal getHidlFingerprintSensorProps(int sensorId, + @BiometricManager.Authenticators.Types int strength) { + // The existence of config_udfps_sensor_props indicates that the sensor is UDFPS. + final int[] udfpsProps = getContext().getResources().getIntArray( + com.android.internal.R.array.config_udfps_sensor_props); + + final boolean isUdfps = !ArrayUtils.isEmpty(udfpsProps); + + // config_is_powerbutton_fps indicates whether device has a power button fingerprint sensor. + final boolean isPowerbuttonFps = getContext().getResources().getBoolean( + R.bool.config_is_powerbutton_fps); + + final @FingerprintSensorProperties.SensorType int sensorType; + if (isUdfps) { + sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; + } else if (isPowerbuttonFps) { + sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON; + } else { + sensorType = FingerprintSensorProperties.TYPE_REAR; + } + + // IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT + // cannot be checked. + final boolean resetLockoutRequiresHardwareAuthToken = false; + final int maxEnrollmentsPerUser = getContext().getResources().getInteger( + R.integer.config_fingerprintMaxTemplatesPerUser); + + final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); + if (isUdfps && udfpsProps.length == 3) { + return new FingerprintSensorPropertiesInternal(sensorId, + Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser, + componentInfo, sensorType, resetLockoutRequiresHardwareAuthToken, udfpsProps[0], + udfpsProps[1], udfpsProps[2]); + } else { + return new FingerprintSensorPropertiesInternal(sensorId, + Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser, + componentInfo, sensorType, resetLockoutRequiresHardwareAuthToken); + } + } + + private FaceSensorPropertiesInternal getHidlFaceSensorProps(int sensorId, + @BiometricManager.Authenticators.Types int strength) { + final boolean supportsSelfIllumination = getContext().getResources().getBoolean( + R.bool.config_faceAuthSupportsSelfIllumination); + final int maxTemplatesAllowed = getContext().getResources().getInteger( + R.integer.config_faceMaxTemplatesPerUser); + final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); + final boolean supportsFaceDetect = false; + final boolean resetLockoutRequiresChallenge = true; + return new FaceSensorPropertiesInternal(sensorId, + Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed, + componentInfo, FaceSensorProperties.TYPE_UNKNOWN, supportsFaceDetect, + supportsSelfIllumination, resetLockoutRequiresChallenge); + } + + private SensorPropertiesInternal getHidlIrisSensorProps(int sensorId, + @BiometricManager.Authenticators.Types int strength) { + final int maxEnrollmentsPerUser = 1; + final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); + final boolean resetLockoutRequiresHardwareAuthToken = false; + final boolean resetLockoutRequiresChallenge = false; + return new SensorPropertiesInternal(sensorId, + Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser, + componentInfo, resetLockoutRequiresHardwareAuthToken, + resetLockoutRequiresChallenge); + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java index 25b7add0a7d8..d82847c95dce 100644 --- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java +++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java @@ -146,9 +146,10 @@ public class ClientMonitorCallbackConverter { } } - public void onFeatureGet(boolean success, int feature, boolean value) throws RemoteException { + public void onFeatureGet(boolean success, int[] features, boolean[] featureState) + throws RemoteException { if (mFaceServiceReceiver != null) { - mFaceServiceReceiver.onFeatureGet(success, feature, value); + mFaceServiceReceiver.onFeatureGet(success, features, featureState); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java index 0002ad249376..0bc4f1b54d59 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java @@ -36,7 +36,7 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { private final IFaceService mFaceService; private final int mSensorId; - public FaceAuthenticator(IFaceService faceService, int sensorId) throws RemoteException { + public FaceAuthenticator(IFaceService faceService, int sensorId) { mFaceService = faceService; mSensorId = sensorId; } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java index ada84769b9ef..779558e8893e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java @@ -57,7 +57,6 @@ import com.android.internal.widget.LockPatternUtils; import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.biometrics.Utils; -import com.android.server.biometrics.sensors.BiometricServiceCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; @@ -76,7 +75,7 @@ import java.util.List; * The service is responsible for maintaining a list of clients and dispatching all * face-related events. */ -public class FaceService extends SystemService implements BiometricServiceCallback { +public class FaceService extends SystemService { protected static final String TAG = "FaceService"; @@ -618,72 +617,85 @@ public class FaceService extends SystemService implements BiometricServiceCallba new ClientMonitorCallbackConverter(receiver), opPackageName); } - @Override // Binder call - public void initializeConfiguration(int sensorId, - @BiometricManager.Authenticators.Types int strength) { - Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - mServiceProviders.add( - new Face10(getContext(), sensorId, strength, mLockoutResetDispatcher)); - } - } - - public FaceService(Context context) { - super(context); - mServiceWrapper = new FaceServiceWrapper(); - mLockoutResetDispatcher = new LockoutResetDispatcher(context); - mLockPatternUtils = new LockPatternUtils(context); - mServiceProviders = new ArrayList<>(); - } - - @Override - public void onBiometricServiceReady() { - final IBiometricService biometricService = IBiometricService.Stub.asInterface( - ServiceManager.getService(Context.BIOMETRIC_SERVICE)); - - final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR); - if (instances == null || instances.length == 0) { - return; + private void addHidlProviders(@NonNull List<FaceSensorPropertiesInternal> hidlSensors) { + for (FaceSensorPropertiesInternal hidlSensor : hidlSensors) { + mServiceProviders.add( + new Face10(getContext(), hidlSensor, mLockoutResetDispatcher)); + } } - // If for some reason the HAL is not started before the system service, do not block - // the rest of system server. Put this on a background thread. - final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, - true /* allowIo */); - thread.start(); - final Handler handler = new Handler(thread.getLooper()); - - handler.post(() -> { + private void addAidlProviders() { + final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR); + if (instances == null || instances.length == 0) { + return; + } for (String instance : instances) { final String fqName = IFace.DESCRIPTOR + "/" + instance; final IFace face = IFace.Stub.asInterface( - ServiceManager.waitForDeclaredService(fqName)); + Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName))); + if (face == null) { + Slog.e(TAG, "Unable to get declared service: " + fqName); + continue; + } try { final SensorProps[] props = face.getSensorProps(); final FaceProvider provider = new FaceProvider(getContext(), props, instance, mLockoutResetDispatcher); mServiceProviders.add(provider); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception in getSensorProps: " + fqName); + } + } + } - // Register each sensor individually with BiometricService - for (SensorProps prop : props) { - final int sensorId = prop.commonProps.sensorId; - @BiometricManager.Authenticators.Types int strength = - Utils.propertyStrengthToAuthenticatorStrength( - prop.commonProps.sensorStrength); - final FaceAuthenticator authenticator = - new FaceAuthenticator(mServiceWrapper, sensorId); + @Override // Binder call + public void registerAuthenticators( + @NonNull List<FaceSensorPropertiesInternal> hidlSensors) { + Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + + // Some HAL might not be started before the system service and will cause the code below + // to wait, and some of the operations below might take a significant amount of time to + // complete (calls to the HALs). To avoid blocking the rest of system server we put + // this on a background thread. + final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, + true /* allowIo */); + thread.start(); + final Handler handler = new Handler(thread.getLooper()); + + handler.post(() -> { + addHidlProviders(hidlSensors); + addAidlProviders(); + + final IBiometricService biometricService = IBiometricService.Stub.asInterface( + ServiceManager.getService(Context.BIOMETRIC_SERVICE)); + + // Register each sensor individually with BiometricService + for (ServiceProvider provider : mServiceProviders) { + final List<FaceSensorPropertiesInternal> props = provider.getSensorProperties(); + for (FaceSensorPropertiesInternal prop : props) { + final int sensorId = prop.sensorId; + final @BiometricManager.Authenticators.Types int strength = + Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength); + final FaceAuthenticator authenticator = new FaceAuthenticator( + mServiceWrapper, sensorId); try { biometricService.registerAuthenticator(sensorId, TYPE_FACE, strength, authenticator); } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when registering sensorId: " - + sensorId); + Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId); } } - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when initializing instance: " + fqName); } - } - }); + }); + } + } + + public FaceService(Context context) { + super(context); + mServiceWrapper = new FaceServiceWrapper(); + mLockoutResetDispatcher = new LockoutResetDispatcher(context); + mLockPatternUtils = new LockPatternUtils(context); + mServiceProviders = new ArrayList<>(); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java index 5d713f35f925..043260c840bc 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java @@ -24,11 +24,14 @@ import android.hardware.biometrics.face.AuthenticationFrame; import android.hardware.biometrics.face.BaseFrame; import android.hardware.biometrics.face.Cell; import android.hardware.biometrics.face.EnrollmentFrame; +import android.hardware.biometrics.face.EnrollmentStage; import android.hardware.biometrics.face.Error; import android.hardware.face.FaceAuthenticationFrame; import android.hardware.face.FaceDataFrame; import android.hardware.face.FaceEnrollCell; import android.hardware.face.FaceEnrollFrame; +import android.hardware.face.FaceEnrollStages; +import android.hardware.face.FaceEnrollStages.FaceEnrollStage; /** * Utilities for converting from hardware to framework-defined AIDL models. @@ -38,92 +41,107 @@ final class AidlConversionUtils { private AidlConversionUtils() { } - public static @BiometricFaceConstants.FaceError int toFrameworkError(byte aidlError) { - if (aidlError == Error.UNKNOWN) { - // No framework constant available - return BiometricFaceConstants.FACE_ERROR_UNKNOWN; - } else if (aidlError == Error.HW_UNAVAILABLE) { - return BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE; - } else if (aidlError == Error.UNABLE_TO_PROCESS) { - return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS; - } else if (aidlError == Error.TIMEOUT) { - return BiometricFaceConstants.FACE_ERROR_TIMEOUT; - } else if (aidlError == Error.NO_SPACE) { - return BiometricFaceConstants.FACE_ERROR_NO_SPACE; - } else if (aidlError == Error.CANCELED) { - return BiometricFaceConstants.FACE_ERROR_CANCELED; - } else if (aidlError == Error.UNABLE_TO_REMOVE) { - return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_REMOVE; - } else if (aidlError == Error.VENDOR) { - return BiometricFaceConstants.FACE_ERROR_VENDOR; - } else if (aidlError == Error.REENROLL_REQUIRED) { - return BiometricFaceConstants.BIOMETRIC_ERROR_RE_ENROLL; - } else { - return BiometricFaceConstants.FACE_ERROR_UNKNOWN; + @BiometricFaceConstants.FaceError + public static int toFrameworkError(byte aidlError) { + switch (aidlError) { + case Error.HW_UNAVAILABLE: + return BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE; + case Error.UNABLE_TO_PROCESS: + return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS; + case Error.TIMEOUT: + return BiometricFaceConstants.FACE_ERROR_TIMEOUT; + case Error.NO_SPACE: + return BiometricFaceConstants.FACE_ERROR_NO_SPACE; + case Error.CANCELED: + return BiometricFaceConstants.FACE_ERROR_CANCELED; + case Error.UNABLE_TO_REMOVE: + return BiometricFaceConstants.FACE_ERROR_UNABLE_TO_REMOVE; + case Error.VENDOR: + return BiometricFaceConstants.FACE_ERROR_VENDOR; + case Error.REENROLL_REQUIRED: + return BiometricFaceConstants.BIOMETRIC_ERROR_RE_ENROLL; + case Error.UNKNOWN: + default: + return BiometricFaceConstants.FACE_ERROR_UNKNOWN; } } - public static @BiometricFaceConstants.FaceAcquired int toFrameworkAcquiredInfo( - byte aidlAcquired) { - if (aidlAcquired == AcquiredInfo.UNKNOWN) { - return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; - } else if (aidlAcquired == AcquiredInfo.GOOD) { - return BiometricFaceConstants.FACE_ACQUIRED_GOOD; - } else if (aidlAcquired == AcquiredInfo.INSUFFICIENT) { - return BiometricFaceConstants.FACE_ACQUIRED_INSUFFICIENT; - } else if (aidlAcquired == AcquiredInfo.TOO_BRIGHT) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT; - } else if (aidlAcquired == AcquiredInfo.TOO_DARK) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK; - } else if (aidlAcquired == AcquiredInfo.TOO_CLOSE) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_CLOSE; - } else if (aidlAcquired == AcquiredInfo.TOO_FAR) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_FAR; - } else if (aidlAcquired == AcquiredInfo.FACE_TOO_HIGH) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH; - } else if (aidlAcquired == AcquiredInfo.FACE_TOO_LOW) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW; - } else if (aidlAcquired == AcquiredInfo.FACE_TOO_RIGHT) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT; - } else if (aidlAcquired == AcquiredInfo.FACE_TOO_LEFT) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT; - } else if (aidlAcquired == AcquiredInfo.POOR_GAZE) { - return BiometricFaceConstants.FACE_ACQUIRED_POOR_GAZE; - } else if (aidlAcquired == AcquiredInfo.NOT_DETECTED) { - return BiometricFaceConstants.FACE_ACQUIRED_NOT_DETECTED; - } else if (aidlAcquired == AcquiredInfo.TOO_MUCH_MOTION) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_MUCH_MOTION; - } else if (aidlAcquired == AcquiredInfo.RECALIBRATE) { - return BiometricFaceConstants.FACE_ACQUIRED_RECALIBRATE; - } else if (aidlAcquired == AcquiredInfo.TOO_DIFFERENT) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_DIFFERENT; - } else if (aidlAcquired == AcquiredInfo.TOO_SIMILAR) { - return BiometricFaceConstants.FACE_ACQUIRED_TOO_SIMILAR; - } else if (aidlAcquired == AcquiredInfo.PAN_TOO_EXTREME) { - return BiometricFaceConstants.FACE_ACQUIRED_PAN_TOO_EXTREME; - } else if (aidlAcquired == AcquiredInfo.TILT_TOO_EXTREME) { - return BiometricFaceConstants.FACE_ACQUIRED_TILT_TOO_EXTREME; - } else if (aidlAcquired == AcquiredInfo.ROLL_TOO_EXTREME) { - return BiometricFaceConstants.FACE_ACQUIRED_ROLL_TOO_EXTREME; - } else if (aidlAcquired == AcquiredInfo.FACE_OBSCURED) { - return BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED; - } else if (aidlAcquired == AcquiredInfo.START) { - return BiometricFaceConstants.FACE_ACQUIRED_START; - } else if (aidlAcquired == AcquiredInfo.SENSOR_DIRTY) { - return BiometricFaceConstants.FACE_ACQUIRED_SENSOR_DIRTY; - } else if (aidlAcquired == AcquiredInfo.VENDOR) { - return BiometricFaceConstants.FACE_ACQUIRED_VENDOR; - } else if (aidlAcquired == AcquiredInfo.FIRST_FRAME_RECEIVED) { - // No framework constant available - return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; - } else if (aidlAcquired == AcquiredInfo.DARK_GLASSES_DETECTED) { - // No framework constant available - return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; - } else if (aidlAcquired == AcquiredInfo.MOUTH_COVERING_DETECTED) { - // No framework constant available - return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; - } else { - return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; + @BiometricFaceConstants.FaceAcquired + public static int toFrameworkAcquiredInfo(byte aidlAcquiredInfo) { + switch (aidlAcquiredInfo) { + case AcquiredInfo.GOOD: + return BiometricFaceConstants.FACE_ACQUIRED_GOOD; + case AcquiredInfo.INSUFFICIENT: + return BiometricFaceConstants.FACE_ACQUIRED_INSUFFICIENT; + case AcquiredInfo.TOO_BRIGHT: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT; + case AcquiredInfo.TOO_DARK: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK; + case AcquiredInfo.TOO_CLOSE: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_CLOSE; + case AcquiredInfo.TOO_FAR: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_FAR; + case AcquiredInfo.FACE_TOO_HIGH: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH; + case AcquiredInfo.FACE_TOO_LOW: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW; + case AcquiredInfo.FACE_TOO_RIGHT: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT; + case AcquiredInfo.FACE_TOO_LEFT: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT; + case AcquiredInfo.POOR_GAZE: + return BiometricFaceConstants.FACE_ACQUIRED_POOR_GAZE; + case AcquiredInfo.NOT_DETECTED: + return BiometricFaceConstants.FACE_ACQUIRED_NOT_DETECTED; + case AcquiredInfo.TOO_MUCH_MOTION: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_MUCH_MOTION; + case AcquiredInfo.RECALIBRATE: + return BiometricFaceConstants.FACE_ACQUIRED_RECALIBRATE; + case AcquiredInfo.TOO_DIFFERENT: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_DIFFERENT; + case AcquiredInfo.TOO_SIMILAR: + return BiometricFaceConstants.FACE_ACQUIRED_TOO_SIMILAR; + case AcquiredInfo.PAN_TOO_EXTREME: + return BiometricFaceConstants.FACE_ACQUIRED_PAN_TOO_EXTREME; + case AcquiredInfo.TILT_TOO_EXTREME: + return BiometricFaceConstants.FACE_ACQUIRED_TILT_TOO_EXTREME; + case AcquiredInfo.ROLL_TOO_EXTREME: + return BiometricFaceConstants.FACE_ACQUIRED_ROLL_TOO_EXTREME; + case AcquiredInfo.FACE_OBSCURED: + return BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED; + case AcquiredInfo.START: + return BiometricFaceConstants.FACE_ACQUIRED_START; + case AcquiredInfo.SENSOR_DIRTY: + return BiometricFaceConstants.FACE_ACQUIRED_SENSOR_DIRTY; + case AcquiredInfo.VENDOR: + return BiometricFaceConstants.FACE_ACQUIRED_VENDOR; + case AcquiredInfo.UNKNOWN: + case AcquiredInfo.FIRST_FRAME_RECEIVED: + case AcquiredInfo.DARK_GLASSES_DETECTED: + case AcquiredInfo.MOUTH_COVERING_DETECTED: + default: + return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN; + } + } + + @FaceEnrollStage + public static int toFrameworkEnrollmentStage(int aidlEnrollmentStage) { + switch (aidlEnrollmentStage) { + case EnrollmentStage.FIRST_FRAME_RECEIVED: + return FaceEnrollStages.FIRST_FRAME_RECEIVED; + case EnrollmentStage.WAITING_FOR_CENTERING: + return FaceEnrollStages.WAITING_FOR_CENTERING; + case EnrollmentStage.HOLD_STILL_IN_CENTER: + return FaceEnrollStages.HOLD_STILL_IN_CENTER; + case EnrollmentStage.ENROLLING_MOVEMENT_1: + return FaceEnrollStages.ENROLLING_MOVEMENT_1; + case EnrollmentStage.ENROLLING_MOVEMENT_2: + return FaceEnrollStages.ENROLLING_MOVEMENT_2; + case EnrollmentStage.ENROLLMENT_FINISHED: + return FaceEnrollStages.ENROLLMENT_FINISHED; + case EnrollmentStage.UNKNOWN: + default: + return FaceEnrollStages.UNKNOWN; } } @@ -135,7 +153,9 @@ final class AidlConversionUtils { @NonNull public static FaceEnrollFrame toFrameworkEnrollmentFrame(@NonNull EnrollmentFrame frame) { - return new FaceEnrollFrame(toFrameworkCell(frame.cell), frame.stage, + return new FaceEnrollFrame( + toFrameworkCell(frame.cell), + toFrameworkEnrollmentStage(frame.stage), toFrameworkBaseFrame(frame.data)); } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java index ca9be67914e3..87269237bc85 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java @@ -105,7 +105,7 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { } @Override - public void onFeatureGet(boolean success, int feature, boolean value) { + public void onFeatureGet(boolean success, int[] features, boolean[] featureState) { } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.java new file mode 100644 index 000000000000..12f3e87dd37e --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClient.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.biometrics.sensors.face.aidl; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.hardware.biometrics.BiometricFaceConstants; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.face.Feature; +import android.hardware.biometrics.face.IFace; +import android.hardware.biometrics.face.ISession; +import android.os.IBinder; +import android.os.RemoteException; +import android.provider.Settings; +import android.util.Slog; + +import com.android.server.biometrics.BiometricsProto; +import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; +import com.android.server.biometrics.sensors.ErrorConsumer; +import com.android.server.biometrics.sensors.HalClientMonitor; + +import java.util.HashMap; +import java.util.Map; + +/** + * Face-specific get feature client for the {@link IFace} AIDL HAL interface. + */ +public class FaceGetFeatureClient extends HalClientMonitor<ISession> implements ErrorConsumer { + + private static final String TAG = "FaceGetFeatureClient"; + + private final int mUserId; + + FaceGetFeatureClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon, + @NonNull IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId, + @NonNull String owner, int sensorId) { + super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, + BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN, + BiometricsProtoEnums.CLIENT_UNKNOWN); + mUserId = userId; + } + + @Override + public void unableToStart() { + mCallback.onClientFinished(this, false /* success */); + } + + @Override + public void start(@NonNull Callback callback) { + super.start(callback); + startHalOperation(); + } + + @Override + protected void startHalOperation() { + try { + getFreshDaemon().getFeatures(); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to getFeature", e); + mCallback.onClientFinished(this, false /* success */); + } + } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_GET_FEATURE; + } + + public void onFeatureGet(boolean success, byte[] features) { + HashMap<Integer, Boolean> featureMap = getFeatureMap(); + int[] featuresToSend = new int[featureMap.size()]; + boolean[] featureState = new boolean[featureMap.size()]; + + // The AIDL get feature api states that the presence of a feature means + // it is enabled, while the lack thereof means its disabled. + for (int i = 0; i < features.length; i++) { + Integer feature = convertAidlToFrameworkFeature(features[i]); + if (feature != null) { + featureMap.put(feature, true); + } + } + + int i = 0; + for (Map.Entry<Integer, Boolean> entry : featureMap.entrySet()) { + featuresToSend[i] = entry.getKey(); + featureState[i] = entry.getValue(); + i++; + } + + boolean attentionEnabled = featureMap.get(BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION); + Slog.d(TAG, "Updating attention value for user: " + mUserId + + " to value: " + attentionEnabled); + Settings.Secure.putIntForUser(getContext().getContentResolver(), + Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, + attentionEnabled ? 1 : 0, mUserId); + try { + getListener().onFeatureGet(success, featuresToSend, featureState); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + + mCallback.onClientFinished(this, true /* success */); + } + + private @NonNull HashMap<Integer, Boolean> getFeatureMap() { + HashMap<Integer, Boolean> featureMap = new HashMap<>(); + featureMap.put(BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION, false); + return featureMap; + } + + private Integer convertAidlToFrameworkFeature(byte feature) { + switch (feature) { + case Feature.REQUIRE_ATTENTION: + return new Integer(BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION); + default: + return null; + } + } + + @Override + public void onError(int errorCode, int vendorCode) { + try { + getListener().onFeatureGet(false /* success */, new int[0], new boolean[0]); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + + mCallback.onClientFinished(this, false /* success */); + } + +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java index b8bac402f430..84d239ef2b50 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java @@ -33,6 +33,7 @@ import android.hardware.biometrics.face.SensorProps; import android.hardware.face.Face; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceServiceReceiver; +import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -173,7 +174,9 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { Slog.d(getTag(), "Daemon was null, reconnecting"); mDaemon = IFace.Stub.asInterface( - ServiceManager.waitForDeclaredService(IFace.DESCRIPTOR + "/" + mHalInstanceName)); + Binder.allowBlocking( + ServiceManager.waitForDeclaredService( + IFace.DESCRIPTOR + "/" + mHalInstanceName))); if (mDaemon == null) { Slog.e(getTag(), "Unable to get daemon"); return null; @@ -435,13 +438,36 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { public void scheduleSetFeature(int sensorId, @NonNull IBinder token, int userId, int feature, boolean enabled, @NonNull byte[] hardwareAuthToken, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) { - // TODO(b/171335732): implement this. + mHandler.post(() -> { + final List<Face> faces = FaceUtils.getInstance(sensorId) + .getBiometricsForUser(mContext, userId); + if (faces.isEmpty()) { + Slog.w(getTag(), "Ignoring setFeature, no templates enrolled for user: " + userId); + return; + } + final FaceSetFeatureClient client = new FaceSetFeatureClient(mContext, + mSensors.get(sensorId).getLazySession(), token, + new ClientMonitorCallbackConverter(receiver), userId, + mContext.getOpPackageName(), sensorId, feature, enabled, hardwareAuthToken); + scheduleForSensor(sensorId, client); + }); } @Override public void scheduleGetFeature(int sensorId, @NonNull IBinder token, int userId, int feature, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName) { - // TODO(b/171335732): implement this. + mHandler.post(() -> { + final List<Face> faces = FaceUtils.getInstance(sensorId) + .getBiometricsForUser(mContext, userId); + if (faces.isEmpty()) { + Slog.w(getTag(), "Ignoring getFeature, no templates enrolled for user: " + userId); + return; + } + final FaceGetFeatureClient client = new FaceGetFeatureClient(mContext, + mSensors.get(sensorId).getLazySession(), token, callback, userId, + mContext.getOpPackageName(), sensorId); + scheduleForSensor(sensorId, client); + }); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java new file mode 100644 index 000000000000..c3abfc2ddd0b --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClient.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors.face.aidl; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.BiometricFaceConstants; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.face.Feature; +import android.hardware.biometrics.face.IFace; +import android.hardware.biometrics.face.ISession; +import android.hardware.keymaster.HardwareAuthToken; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.BiometricsProto; +import com.android.server.biometrics.HardwareAuthTokenUtils; +import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; +import com.android.server.biometrics.sensors.ErrorConsumer; +import com.android.server.biometrics.sensors.HalClientMonitor; + +/** + * Face-specific get feature client for the {@link IFace} AIDL HAL interface. + */ +public class FaceSetFeatureClient extends HalClientMonitor<ISession> implements ErrorConsumer { + + private static final String TAG = "FaceSetFeatureClient"; + + private final int mFeature; + private final boolean mEnabled; + private final HardwareAuthToken mHardwareAuthToken; + + FaceSetFeatureClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon, + @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, + @NonNull String owner, int sensorId, int feature, boolean enabled, + byte[] hardwareAuthToken) { + super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, + BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN, + BiometricsProtoEnums.CLIENT_UNKNOWN); + mFeature = feature; + mEnabled = enabled; + mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken); + } + + @Override + public void unableToStart() { + try { + getListener().onFeatureSet(false /* success */, mFeature); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to send error", e); + } + } + + @Override + public void start(@NonNull Callback callback) { + super.start(callback); + startHalOperation(); + } + + @Override + protected void startHalOperation() { + try { + getFreshDaemon() + .setFeature(mHardwareAuthToken, + convertFrameworkToAidlFeature(mFeature), mEnabled); + } catch (RemoteException | IllegalArgumentException e) { + Slog.e(TAG, "Unable to set feature: " + mFeature + " to enabled: " + mEnabled, e); + mCallback.onClientFinished(this, false /* success */); + } + } + + @Override + public int getProtoEnum() { + return BiometricsProto.CM_SET_FEATURE; + } + + public void onFeatureSet(boolean success) { + try { + getListener().onFeatureSet(success, mFeature); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + + mCallback.onClientFinished(this, true /* success */); + } + + private byte convertFrameworkToAidlFeature(int feature) throws IllegalArgumentException { + switch (feature) { + case BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION: + return Feature.REQUIRE_ATTENTION; + default: + Slog.e(TAG, "Unsupported feature : " + feature); + throw new IllegalArgumentException(); + } + } + + @Override + public void onError(int errorCode, int vendorCode) { + try { + getListener().onFeatureSet(false /* success */, mFeature); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + + mCallback.onClientFinished(this, false /* success */); + } + +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java index b11bc8745b2c..724531ebcf42 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java @@ -377,12 +377,32 @@ public class Sensor { @Override public void onFeaturesRetrieved(byte[] features) { + mHandler.post(() -> { + final BaseClientMonitor client = mScheduler.getCurrentClient(); + if (!(client instanceof FaceGetFeatureClient)) { + Slog.e(mTag, "onFeaturesRetrieved for non-get feature consumer: " + + Utils.getClientName(client)); + return; + } + final FaceGetFeatureClient faceGetFeatureClient = (FaceGetFeatureClient) client; + faceGetFeatureClient.onFeatureGet(true /* success */, features); + }); } @Override public void onFeatureSet(byte feature) { + mHandler.post(() -> { + final BaseClientMonitor client = mScheduler.getCurrentClient(); + if (!(client instanceof FaceSetFeatureClient)) { + Slog.e(mTag, "onFeatureSet for non-set consumer: " + + Utils.getClientName(client)); + return; + } + final FaceSetFeatureClient faceSetFeatureClient = (FaceSetFeatureClient) client; + faceSetFeatureClient.onFeatureSet(true /* success */); + }); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java index e8668ed1b6c5..f8067670f61f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java @@ -94,7 +94,7 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { } @Override - public void onFeatureGet(boolean success, int feature, boolean value) { + public void onFeatureGet(boolean success, int[] features, boolean[] featureState) { } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java index a40155b2df7d..5dfc5907060f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java @@ -25,15 +25,12 @@ import android.content.Context; import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricFaceConstants; -import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricsProtoEnums; -import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback; import android.hardware.face.Face; -import android.hardware.face.FaceSensorProperties; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceServiceReceiver; import android.os.Binder; @@ -51,7 +48,6 @@ import android.provider.Settings; import android.util.Slog; import android.util.proto.ProtoOutputStream; -import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.server.biometrics.SensorServiceStateProto; @@ -66,7 +62,6 @@ import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.EnumerateConsumer; import com.android.server.biometrics.sensors.ErrorConsumer; import com.android.server.biometrics.sensors.HalClientMonitor; -import com.android.server.biometrics.sensors.Interruptable; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; import com.android.server.biometrics.sensors.PerformanceTracker; @@ -327,19 +322,13 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } } - @VisibleForTesting - Face10(@NonNull Context context, int sensorId, - @BiometricManager.Authenticators.Types int strength, + @VisibleForTesting Face10(@NonNull Context context, + @NonNull FaceSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher, - boolean supportsSelfIllumination, int maxTemplatesAllowed, @NonNull BiometricScheduler scheduler) { - mSensorProperties = new FaceSensorPropertiesInternal(sensorId, - Utils.authenticatorStrengthToPropertyStrength(strength), - maxTemplatesAllowed, new ArrayList<ComponentInfoInternal>() /* componentInfo */, - FaceSensorProperties.TYPE_UNKNOWN, false /* supportsFaceDetect */, - supportsSelfIllumination, true /* resetLockoutRequiresChallenge */); + mSensorProperties = sensorProps; mContext = context; - mSensorId = sensorId; + mSensorId = sensorProps.sensorId; mScheduler = scheduler; mHandler = new Handler(Looper.getMainLooper()); mUsageStats = new UsageStats(context); @@ -347,8 +336,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { mLazyDaemon = Face10.this::getDaemon; mLockoutTracker = new LockoutHalImpl(); mLockoutResetDispatcher = lockoutResetDispatcher; - mHalResultController = new HalResultController(sensorId, context, mHandler, mScheduler, - mLockoutTracker, lockoutResetDispatcher); + mHalResultController = new HalResultController(sensorProps.sensorId, context, mHandler, + mScheduler, mLockoutTracker, lockoutResetDispatcher); mHalResultController.setCallback(() -> { mDaemon = null; mCurrentUserId = UserHandle.USER_NULL; @@ -361,12 +350,9 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } } - public Face10(@NonNull Context context, int sensorId, - @BiometricManager.Authenticators.Types int strength, + public Face10(@NonNull Context context, @NonNull FaceSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher) { - this(context, sensorId, strength, lockoutResetDispatcher, - context.getResources().getBoolean(R.bool.config_faceAuthSupportsSelfIllumination), - context.getResources().getInteger(R.integer.config_faceMaxTemplatesPerUser), + this(context, sensorProps, lockoutResetDispatcher, new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */)); } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java index b1083d410fec..7821601c8433 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java @@ -58,7 +58,7 @@ public class FaceGetFeatureClient extends HalClientMonitor<IBiometricsFace> { public void unableToStart() { try { if (getListener() != null) { - getListener().onFeatureGet(false /* success */, mFeature, false /* value */); + getListener().onFeatureGet(false /* success */, new int[0], new boolean[0]); } } catch (RemoteException e) { Slog.e(TAG, "Unable to send error", e); @@ -75,9 +75,14 @@ public class FaceGetFeatureClient extends HalClientMonitor<IBiometricsFace> { protected void startHalOperation() { try { final OptionalBool result = getFreshDaemon().getFeature(mFeature, mFaceId); + int[] features = new int[1]; + boolean[] featureState = new boolean[1]; + features[0] = mFeature; + featureState[0] = result.value; mValue = result.value; + if (getListener() != null) { - getListener().onFeatureGet(result.status == Status.OK, mFeature, mValue); + getListener().onFeatureGet(result.status == Status.OK, features, featureState); } mCallback.onClientFinished(this, true /* success */); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java index 81096802a78b..1e5942930b01 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java @@ -36,8 +36,7 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub private final IFingerprintService mFingerprintService; private final int mSensorId; - public FingerprintAuthenticator(IFingerprintService fingerprintService, int sensorId) - throws RemoteException { + public FingerprintAuthenticator(IFingerprintService fingerprintService, int sensorId) { mFingerprintService = fingerprintService; mSensorId = sensorId; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index b780222da380..39b7a74caa52 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -50,6 +50,7 @@ import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintServiceReceiver; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.IFingerprintClientActiveCallback; import android.hardware.fingerprint.IFingerprintService; import android.hardware.fingerprint.IFingerprintServiceReceiver; @@ -61,6 +62,7 @@ import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; import android.os.Process; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -71,12 +73,12 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.DumpUtils; import com.android.internal.widget.LockPatternUtils; import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.biometrics.Utils; -import com.android.server.biometrics.sensors.BiometricServiceCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; @@ -96,18 +98,26 @@ import java.util.concurrent.Executor; * The service is responsible for maintaining a list of clients and dispatching all * fingerprint-related events. */ -public class FingerprintService extends SystemService implements BiometricServiceCallback { +public class FingerprintService extends SystemService { protected static final String TAG = "FingerprintService"; + private final Object mLock = new Object(); private final AppOpsManager mAppOps; private final LockoutResetDispatcher mLockoutResetDispatcher; private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher; private final LockPatternUtils mLockPatternUtils; private final FingerprintServiceWrapper mServiceWrapper; - @NonNull private List<ServiceProvider> mServiceProviders; + @NonNull private final List<ServiceProvider> mServiceProviders; @NonNull private final FingerprintStateCallback mFingerprintStateCallback; + @GuardedBy("mLock") + @NonNull private final RemoteCallbackList<IFingerprintAuthenticatorsRegisteredCallback> + mAuthenticatorsRegisteredCallbacks; + + @GuardedBy("mLock") + @NonNull private final List<FingerprintSensorPropertiesInternal> mSensorProps; + /** * Registers FingerprintStateListener in list stored by FingerprintService * @param listener new FingerprintStateListener being added @@ -745,7 +755,7 @@ public class FingerprintService extends SystemService implements BiometricServic @Override // Binder call public void resetLockout(IBinder token, int sensorId, int userId, - @Nullable byte [] hardwareAuthToken, String opPackageName) { + @Nullable byte[] hardwareAuthToken, String opPackageName) { Utils.checkPermission(getContext(), RESET_FINGERPRINT_LOCKOUT); final ServiceProvider provider = getProviderForSensor(sensorId); @@ -775,24 +785,119 @@ public class FingerprintService extends SystemService implements BiometricServic mGestureAvailabilityDispatcher.removeCallback(callback); } + private void addHidlProviders(List<FingerprintSensorPropertiesInternal> hidlSensors) { + for (FingerprintSensorPropertiesInternal hidlSensor : hidlSensors) { + final Fingerprint21 fingerprint21; + if ((Build.IS_USERDEBUG || Build.IS_ENG) + && getContext().getResources().getBoolean(R.bool.allow_test_udfps) + && Settings.Secure.getIntForUser(getContext().getContentResolver(), + Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */, + UserHandle.USER_CURRENT) != 0) { + fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), hidlSensor, + mLockoutResetDispatcher, mGestureAvailabilityDispatcher); + } else { + fingerprint21 = Fingerprint21.newInstance(getContext(), hidlSensor, + mLockoutResetDispatcher, mGestureAvailabilityDispatcher); + } + mServiceProviders.add(fingerprint21); + } + } + + private void addAidlProviders() { + final String[] instances = ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR); + if (instances == null || instances.length == 0) { + return; + } + for (String instance : instances) { + final String fqName = IFingerprint.DESCRIPTOR + "/" + instance; + final IFingerprint fp = IFingerprint.Stub.asInterface( + ServiceManager.waitForDeclaredService(fqName)); + if (fp == null) { + Slog.e(TAG, "Unable to get declared service: " + fqName); + continue; + } + try { + final SensorProps[] props = fp.getSensorProps(); + final FingerprintProvider provider = + new FingerprintProvider(getContext(), props, instance, + mLockoutResetDispatcher, mGestureAvailabilityDispatcher); + mServiceProviders.add(provider); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception in getSensorProps: " + fqName); + } + } + } + @Override // Binder call - public void initializeConfiguration(int sensorId, - @BiometricManager.Authenticators.Types int strength) { + public void registerAuthenticators( + @NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - final Fingerprint21 fingerprint21; - if ((Build.IS_USERDEBUG || Build.IS_ENG) - && getContext().getResources().getBoolean(R.bool.allow_test_udfps) - && Settings.Secure.getIntForUser(getContext().getContentResolver(), - Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */, - UserHandle.USER_CURRENT) != 0) { - fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), sensorId, - strength, mLockoutResetDispatcher, mGestureAvailabilityDispatcher); - } else { - fingerprint21 = Fingerprint21.newInstance(getContext(), sensorId, strength, - mLockoutResetDispatcher, mGestureAvailabilityDispatcher); + // Some HAL might not be started before the system service and will cause the code below + // to wait, and some of the operations below might take a significant amount of time to + // complete (calls to the HALs). To avoid blocking the rest of system server we put + // this on a background thread. + final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, + true /* allowIo */); + thread.start(); + final Handler handler = new Handler(thread.getLooper()); + + handler.post(() -> { + addHidlProviders(hidlSensors); + addAidlProviders(); + + final IBiometricService biometricService = IBiometricService.Stub.asInterface( + ServiceManager.getService(Context.BIOMETRIC_SERVICE)); + + // Register each sensor individually with BiometricService + for (ServiceProvider provider : mServiceProviders) { + final List<FingerprintSensorPropertiesInternal> props = + provider.getSensorProperties(); + for (FingerprintSensorPropertiesInternal prop : props) { + final int sensorId = prop.sensorId; + final @BiometricManager.Authenticators.Types int strength = + Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength); + final FingerprintAuthenticator authenticator = new FingerprintAuthenticator( + mServiceWrapper, sensorId); + try { + biometricService.registerAuthenticator(sensorId, TYPE_FINGERPRINT, + strength, authenticator); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId); + } + } + } + + synchronized (mLock) { + for (ServiceProvider provider : mServiceProviders) { + mSensorProps.addAll(provider.getSensorProperties()); + } + } + + broadcastAllAuthenticatorsRegistered(); + }); + } + + @Override + public void addAuthenticatorsRegisteredCallback( + IFingerprintAuthenticatorsRegisteredCallback callback) { + Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + if (callback == null) { + Slog.e(TAG, "addAuthenticatorsRegisteredCallback, callback is null"); + return; + } + + final boolean registered; + final boolean hasSensorProps; + synchronized (mLock) { + registered = mAuthenticatorsRegisteredCallbacks.register(callback); + hasSensorProps = !mSensorProps.isEmpty(); + } + if (registered && hasSensorProps) { + broadcastAllAuthenticatorsRegistered(); + } else if (!registered) { + Slog.e(TAG, "addAuthenticatorsRegisteredCallback failed to register callback"); } - mServiceProviders.add(fingerprint21); } @Override @@ -843,58 +948,40 @@ public class FingerprintService extends SystemService implements BiometricServic mLockPatternUtils = new LockPatternUtils(context); mServiceProviders = new ArrayList<>(); mFingerprintStateCallback = new FingerprintStateCallback(); + mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>(); + mSensorProps = new ArrayList<>(); } - @Override - public void onBiometricServiceReady() { - final IBiometricService biometricService = IBiometricService.Stub.asInterface( - ServiceManager.getService(Context.BIOMETRIC_SERVICE)); - - final String[] instances = ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR); - if (instances == null || instances.length == 0) { - return; + // Notifies the callbacks that all of the authenticators have been registered and removes the + // invoked callbacks from the callback list. + private void broadcastAllAuthenticatorsRegistered() { + // Make a local copy of the data so it can be used outside of the synchronized block when + // making Binder calls. + final List<IFingerprintAuthenticatorsRegisteredCallback> callbacks = new ArrayList<>(); + final List<FingerprintSensorPropertiesInternal> props; + synchronized (mLock) { + if (!mSensorProps.isEmpty()) { + props = new ArrayList<>(mSensorProps); + } else { + Slog.e(TAG, "mSensorProps is empty"); + return; + } + final int n = mAuthenticatorsRegisteredCallbacks.beginBroadcast(); + for (int i = 0; i < n; ++i) { + final IFingerprintAuthenticatorsRegisteredCallback cb = + mAuthenticatorsRegisteredCallbacks.getBroadcastItem(i); + callbacks.add(cb); + mAuthenticatorsRegisteredCallbacks.unregister(cb); + } + mAuthenticatorsRegisteredCallbacks.finishBroadcast(); } - - // If for some reason the HAL is not started before the system service, do not block - // the rest of system server. Put this on a background thread. - final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, - true /* allowIo */); - thread.start(); - final Handler handler = new Handler(thread.getLooper()); - - handler.post(() -> { - for (String instance : instances) { - final String fqName = IFingerprint.DESCRIPTOR + "/" + instance; - final IFingerprint fp = IFingerprint.Stub.asInterface( - ServiceManager.waitForDeclaredService(fqName)); - try { - final SensorProps[] props = fp.getSensorProps(); - final FingerprintProvider provider = - new FingerprintProvider(getContext(), props, instance, - mLockoutResetDispatcher, mGestureAvailabilityDispatcher); - mServiceProviders.add(provider); - - // Register each sensor individually with BiometricService - for (SensorProps prop : props) { - final int sensorId = prop.commonProps.sensorId; - @BiometricManager.Authenticators.Types int strength = - Utils.propertyStrengthToAuthenticatorStrength( - prop.commonProps.sensorStrength); - final FingerprintAuthenticator authenticator = - new FingerprintAuthenticator(mServiceWrapper, sensorId); - try { - biometricService.registerAuthenticator(sensorId, - TYPE_FINGERPRINT, strength, authenticator); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when registering sensorId: " - + sensorId); - } - } - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when initializing instance: " + fqName); - } + for (IFingerprintAuthenticatorsRegisteredCallback cb : callbacks) { + try { + cb.onAllAuthenticatorsRegistered(props); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception in onAllAuthenticatorsRegistered", e); } - }); + } } @Override @@ -939,12 +1026,9 @@ public class FingerprintService extends SystemService implements BiometricServic @NonNull private List<FingerprintSensorPropertiesInternal> getSensorProperties() { - final List<FingerprintSensorPropertiesInternal> properties = new ArrayList<>(); - - for (ServiceProvider provider : mServiceProviders) { - properties.addAll(provider.getSensorProperties()); + synchronized (mLock) { + return mSensorProps; } - return properties; } @NonNull diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index ebfd5347241d..3528690e6459 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -26,9 +26,7 @@ import android.app.UserSwitchObserver; import android.content.Context; import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricConstants; -import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricsProtoEnums; -import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; @@ -50,9 +48,7 @@ import android.os.UserManager; import android.util.Slog; import android.util.proto.ProtoOutputStream; -import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.server.biometrics.SensorServiceStateProto; import com.android.server.biometrics.SensorStateProto; @@ -314,17 +310,22 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } } - Fingerprint21(@NonNull Context context, @NonNull BiometricScheduler scheduler, - @NonNull Handler handler, int sensorId, - @BiometricManager.Authenticators.Types int strength, + Fingerprint21(@NonNull Context context, + @NonNull FingerprintSensorPropertiesInternal sensorProps, + @NonNull BiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull HalResultController controller) { mContext = context; - mSensorId = sensorId; + + mSensorProperties = sensorProps; + mSensorId = sensorProps.sensorId; + mIsUdfps = sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL + || sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC; + mIsPowerbuttonFps = sensorProps.sensorType == FingerprintSensorProperties.TYPE_POWER_BUTTON; + mScheduler = scheduler; mHandler = handler; mActivityTaskManager = ActivityTaskManager.getInstance(); - mTaskStackListener = new BiometricTaskStackListener(); mAuthenticatorIds = Collections.synchronizedMap(new HashMap<>()); mLazyDaemon = Fingerprint21.this::getDaemon; @@ -341,46 +342,20 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } catch (RemoteException e) { Slog.e(TAG, "Unable to register user switch observer"); } - - // TODO(b/179175438): Remove this code block after transition to AIDL. - // The existence of config_udfps_sensor_props indicates that the sensor is UDFPS. - mIsUdfps = !ArrayUtils.isEmpty( - mContext.getResources().getIntArray(R.array.config_udfps_sensor_props)); - - // config_is_powerbutton_fps indicates whether device has a power button fingerprint sensor. - mIsPowerbuttonFps = mContext.getResources().getBoolean(R.bool.config_is_powerbutton_fps); - - final @FingerprintSensorProperties.SensorType int sensorType; - if (mIsUdfps) { - sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; - } else if (mIsPowerbuttonFps) { - sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON; - } else { - sensorType = FingerprintSensorProperties.TYPE_REAR; - } - - // IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT - // cannot be checked - final boolean resetLockoutRequiresHardwareAuthToken = false; - final int maxEnrollmentsPerUser = mContext.getResources() - .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser); - - mSensorProperties = new FingerprintSensorPropertiesInternal(context, sensorId, - Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser, - new ArrayList<ComponentInfoInternal>() /* componentInfo */, sensorType, - resetLockoutRequiresHardwareAuthToken); } - public static Fingerprint21 newInstance(@NonNull Context context, int sensorId, int strength, + public static Fingerprint21 newInstance(@NonNull Context context, + @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { final Handler handler = new Handler(Looper.getMainLooper()); final BiometricScheduler scheduler = new BiometricScheduler(TAG, gestureAvailabilityDispatcher); - final HalResultController controller = new HalResultController(sensorId, context, handler, + final HalResultController controller = new HalResultController(sensorProps.sensorId, + context, handler, scheduler); - return new Fingerprint21(context, scheduler, handler, sensorId, strength, - lockoutResetDispatcher, controller); + return new Fingerprint21(context, sensorProps, scheduler, handler, lockoutResetDispatcher, + controller); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java index 48419c35e28e..d1020a6ff068 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java @@ -21,8 +21,6 @@ import android.annotation.Nullable; import android.app.trust.TrustManager; import android.content.ContentResolver; import android.content.Context; -import android.hardware.biometrics.BiometricManager; -import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; @@ -39,7 +37,6 @@ import android.util.Slog; import android.util.SparseBooleanArray; import com.android.internal.R; -import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.AuthenticationConsumer; import com.android.server.biometrics.sensors.BaseClientMonitor; import com.android.server.biometrics.sensors.BiometricScheduler; @@ -271,8 +268,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage } } - public static Fingerprint21UdfpsMock newInstance(@NonNull Context context, int sensorId, - @BiometricManager.Authenticators.Types int strength, + public static Fingerprint21UdfpsMock newInstance(@NonNull Context context, + @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { Slog.d(TAG, "Creating Fingerprint23Mock!"); @@ -281,8 +278,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage final TestableBiometricScheduler scheduler = new TestableBiometricScheduler(TAG, gestureAvailabilityDispatcher); final MockHalResultController controller = - new MockHalResultController(sensorId, context, handler, scheduler); - return new Fingerprint21UdfpsMock(context, scheduler, handler, sensorId, strength, + new MockHalResultController(sensorProps.sensorId, context, handler, scheduler); + return new Fingerprint21UdfpsMock(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller); } @@ -407,12 +404,12 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage } private Fingerprint21UdfpsMock(@NonNull Context context, + @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull TestableBiometricScheduler scheduler, - @NonNull Handler handler, int sensorId, - @BiometricManager.Authenticators.Types int strength, + @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull MockHalResultController controller) { - super(context, scheduler, handler, sensorId, strength, lockoutResetDispatcher, controller); + super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller); mScheduler = scheduler; mScheduler.init(this); mHandler = handler; @@ -420,11 +417,11 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage final boolean resetLockoutRequiresHardwareAuthToken = false; final int maxTemplatesAllowed = mContext.getResources() .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser); - mSensorProperties = new FingerprintSensorPropertiesInternal(sensorId, - Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed, - new ArrayList<ComponentInfoInternal>() /* componentInfo */, + mSensorProperties = new FingerprintSensorPropertiesInternal(sensorProps.sensorId, + sensorProps.sensorStrength, maxTemplatesAllowed, sensorProps.componentInfo, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, - resetLockoutRequiresHardwareAuthToken); + resetLockoutRequiresHardwareAuthToken, sensorProps.sensorLocationX, + sensorProps.sensorLocationY, sensorProps.sensorRadius); mMockHalResultController = controller; mUserHasTrust = new SparseBooleanArray(); mTrustManager = context.getSystemService(TrustManager.class); diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java index 1003c26f966e..491818520e3c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java @@ -35,7 +35,7 @@ import com.android.server.biometrics.sensors.LockoutTracker; public final class IrisAuthenticator extends IBiometricAuthenticator.Stub { private final IIrisService mIrisService; - public IrisAuthenticator(IIrisService irisService, int sensorId) throws RemoteException { + public IrisAuthenticator(IIrisService irisService, int sensorId) { mIrisService = irisService; } diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java index 08b24897581f..d684bb843967 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java @@ -17,14 +17,26 @@ package com.android.server.biometrics.sensors.iris; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS; import android.annotation.NonNull; import android.content.Context; +import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.IBiometricService; +import android.hardware.biometrics.SensorPropertiesInternal; import android.hardware.iris.IIrisService; +import android.os.Handler; +import android.os.Process; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Slog; +import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.biometrics.Utils; +import java.util.List; + /** * A service to manage multiple clients that want to access the Iris HAL API. * The service is responsible for maintaining a list of clients and dispatching all @@ -37,22 +49,54 @@ public class IrisService extends SystemService { private static final String TAG = "IrisService"; + private final IrisServiceWrapper mServiceWrapper; + /** * Receives the incoming binder calls from IrisManager. */ private final class IrisServiceWrapper extends IIrisService.Stub { @Override // Binder call - public void initializeConfiguration(int sensorId, int strength) { + public void registerAuthenticators(@NonNull List<SensorPropertiesInternal> hidlSensors) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + + // Some HAL might not be started before the system service and will cause the code below + // to wait, and some of the operations below might take a significant amount of time to + // complete (calls to the HALs). To avoid blocking the rest of system server we put + // this on a background thread. + final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, + true /* allowIo */); + thread.start(); + final Handler handler = new Handler(thread.getLooper()); + + handler.post(() -> { + final IBiometricService biometricService = IBiometricService.Stub.asInterface( + ServiceManager.getService(Context.BIOMETRIC_SERVICE)); + + for (SensorPropertiesInternal hidlSensor : hidlSensors) { + final int sensorId = hidlSensor.sensorId; + final @BiometricManager.Authenticators.Types int strength = + Utils.propertyStrengthToAuthenticatorStrength( + hidlSensor.sensorStrength); + final IrisAuthenticator authenticator = new IrisAuthenticator(mServiceWrapper, + sensorId); + try { + biometricService.registerAuthenticator(sensorId, TYPE_IRIS, strength, + authenticator); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId); + } + } + }); } } public IrisService(@NonNull Context context) { super(context); + mServiceWrapper = new IrisServiceWrapper(); } @Override public void onStart() { - publishBinderService(Context.IRIS_SERVICE, new IrisServiceWrapper()); + publishBinderService(Context.IRIS_SERVICE, mServiceWrapper); } } diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index cf4fe1ef9f97..05b12bad5589 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -16,14 +16,14 @@ package com.android.server.connectivity; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES; import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES; import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS; import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER; import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE; import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS; @@ -33,6 +33,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; +import android.net.ConnectivitySettingsManager; import android.net.IDnsResolver; import android.net.InetAddresses; import android.net.LinkProperties; @@ -131,11 +132,11 @@ public class DnsManager { * Get PrivateDnsConfig. */ public static PrivateDnsConfig getPrivateDnsConfig(Context context) { - final String mode = ConnectivityManager.getPrivateDnsMode(context); + final int mode = ConnectivitySettingsManager.getPrivateDnsMode(context); - final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode); + final boolean useTls = mode != PRIVATE_DNS_MODE_OFF; - if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) { + if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME == mode) { final String specifier = getStringSetting(context.getContentResolver(), PRIVATE_DNS_SPECIFIER); return new PrivateDnsConfig(specifier, null); diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java index 4ecc7594a79c..091e6c4adf4d 100644 --- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java +++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java @@ -27,6 +27,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.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT; import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -227,7 +228,8 @@ public class MultipathPolicyTracker { mNetworkTemplate = new NetworkTemplate( NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId }, null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL, - NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); + NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); mUsageCallback = new UsageCallback() { @Override public void onThresholdReached(int networkType, String subscriberId) { diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java index f572b46a9b58..bc0929c20659 100644 --- a/services/core/java/com/android/server/connectivity/ProxyTracker.java +++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java @@ -55,6 +55,11 @@ public class ProxyTracker { private static final String TAG = ProxyTracker.class.getSimpleName(); private static final boolean DBG = true; + // EXTRA_PROXY_INFO is now @removed. In order to continue sending it, hardcode its value here. + // The Proxy.EXTRA_PROXY_INFO constant is not visible to this code because android.net.Proxy + // a hidden platform constant not visible to mainline modules. + private static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO"; + @NonNull private final Context mContext; @@ -253,7 +258,7 @@ public class ProxyTracker { Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxyInfo); + intent.putExtra(EXTRA_PROXY_INFO, proxyInfo); final long ident = Binder.clearCallingIdentity(); try { mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 2562c26c7e96..4bd1fd8e44cc 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -928,7 +928,6 @@ public class SyncManager { } if (ArrayUtils.isEmpty(accounts)) { - mLogger.log("scheduleSync: no accounts configured, dropping"); return; } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 3f7ec32cb430..789f08fb3187 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -431,8 +431,8 @@ public final class DisplayManagerService extends SystemService { mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper()); mUiHandler = UiThread.getHandler(); mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore); - mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo, - new LogicalDisplayListener()); + mLogicalDisplayMapper = new LogicalDisplayMapper(mContext, mDisplayDeviceRepo, + new LogicalDisplayListener(), mSyncRoot, mHandler); mDisplayModeDirector = new DisplayModeDirector(context, mHandler); mBrightnessSynchronizer = new BrightnessSynchronizer(mContext); Resources resources = mContext.getResources(); @@ -1268,7 +1268,7 @@ public final class DisplayManagerService extends SystemService { DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); if (dpc != null) { - dpc.onDisplayChangedLocked(); + dpc.onDisplayChanged(); } } @@ -1304,12 +1304,23 @@ public final class DisplayManagerService extends SystemService { handleLogicalDisplayChangedLocked(display); } + private void handleLogicalDisplayDeviceStateTransitionLocked(@NonNull LogicalDisplay display) { + final int displayId = display.getDisplayIdLocked(); + final DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); + if (dpc != null) { + dpc.onDeviceStateTransition(); + } + } + private Runnable updateDisplayStateLocked(DisplayDevice device) { // Blank or unblank the display immediately to match the state requested // by the display power controller (if known). DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); + if (display == null) { + return null; + } final int displayId = display.getDisplayIdLocked(); final int state = mDisplayStates.get(displayId); @@ -1453,9 +1464,12 @@ public final class DisplayManagerService extends SystemService { clearViewportsLocked(); // Configure each display device. - mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> { - configureDisplayLocked(t, device); - device.performTraversalLocked(t); + mLogicalDisplayMapper.forEachLocked((LogicalDisplay display) -> { + final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); + if (device != null) { + configureDisplayLocked(t, device); + device.performTraversalLocked(t); + } }); // Tell the input system about these new viewports. @@ -2159,6 +2173,10 @@ public final class DisplayManagerService extends SystemService { case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED: handleLogicalDisplayFrameRateOverridesChangedLocked(display); break; + + case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION: + handleLogicalDisplayDeviceStateTransitionLocked(display); + break; } } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 7c0709e48fa0..3340e3c73fa1 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -780,9 +780,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call * when displays get swapped on foldable devices. For example, different brightness properties * of each display need to be properly reflected in AutomaticBrightnessController. */ - public void onDisplayChangedLocked() { + public void onDisplayChanged() { // TODO: b/175821789 - Support high brightness on multiple (folding) displays - mUniqueDisplayId = mLogicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); mDisplayDeviceConfig = mLogicalDisplay.getPrimaryDisplayDeviceLocked() .getDisplayDeviceConfig(); @@ -790,6 +789,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } /** + * Called when the displays are preparing to transition from one device state to another. + * This process involves turning off some displays so we need updatePowerState() to run and + * calculate the new state. + */ + public void onDeviceStateTransition() { + sendUpdatePowerState(); + } + + /** * Unregisters all listeners and interrupts all running threads; halting future work. * * This method should be called when the DisplayPowerController is no longer in use; i.e. when @@ -1024,7 +1032,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mIgnoreProximityUntilChanged = false; } - if (!mLogicalDisplay.isEnabled() || mScreenOffBecauseOfProximity) { + if (!mLogicalDisplay.isEnabled() + || mLogicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION + || mScreenOffBecauseOfProximity) { state = Display.STATE_OFF; } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 15894199f806..9acb4c8f471a 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -16,6 +16,7 @@ package com.android.server.display; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Point; @@ -65,6 +66,33 @@ import java.util.Objects; final class LogicalDisplay { private static final String TAG = "LogicalDisplay"; + /** + * Phase indicating the logical display's existence is hidden from the rest of the framework. + * This can happen if the current layout has specifically requested to keep this display + * disabled. + */ + static final int DISPLAY_PHASE_DISABLED = -1; + + /** + * Phase indicating that the logical display is going through a layout transition. + * When in this phase, other systems can choose to special case power-state handling of a + * display that might be in a transition. + */ + static final int DISPLAY_PHASE_LAYOUT_TRANSITION = 0; + + /** + * The display is exposed to the rest of the system and its power state is determined by a + * power-request from PowerManager. + */ + static final int DISPLAY_PHASE_ENABLED = 1; + + @IntDef(prefix = {"DISPLAY_PHASE" }, value = { + DISPLAY_PHASE_DISABLED, + DISPLAY_PHASE_LAYOUT_TRANSITION, + DISPLAY_PHASE_ENABLED + }) + @interface DisplayPhase {} + // The layer stack we use when the display has been blanked to prevent any // of its content from appearing. private static final int BLANK_LAYER_STACK = -1; @@ -129,10 +157,12 @@ final class LogicalDisplay { private final Rect mTempDisplayRect = new Rect(); /** - * Indicates that the Logical display is enabled (default). See {@link #setEnabled} for - * more information. + * Indicates the current phase of the display. Generally, phases supersede any + * requests from PowerManager in DPC's calculation for the display state. Only when the + * phase is ENABLED does PowerManager's request for the display take effect. */ - private boolean mIsEnabled = true; + @DisplayPhase + private int mPhase = DISPLAY_PHASE_ENABLED; /** * The UID mappings for refresh rate override @@ -721,27 +751,32 @@ final class LogicalDisplay { return old; } + public void setPhase(@DisplayPhase int phase) { + mPhase = phase; + } + /** - * Sets the LogicalDisplay to be enabled or disabled. If the display is not enabled, - * the system will always set the display to power off, regardless of the global state of the - * device. - * TODO: b/170498827 - Remove when updateDisplayStateLocked is updated. + * Returns the currently set phase for this LogicalDisplay. Phases are used when transitioning + * from one device state to another. {@see LogicalDisplayMapper}. */ - public void setEnabled(boolean isEnabled) { - mIsEnabled = isEnabled; + @DisplayPhase + public int getPhase() { + return mPhase; } /** - * @return {@code true} iff the LogicalDisplay is enabled or {@code false} - * if disabled indicating that the display has been forced to be OFF. + * @return {@code true} if the LogicalDisplay is enabled or {@code false} + * if disabled indicating that the display should be hidden from the rest of the apps and + * framework. */ public boolean isEnabled() { - return mIsEnabled; + // DISPLAY_PHASE_LAYOUT_TRANSITION is still considered an 'enabled' phase. + return mPhase == DISPLAY_PHASE_ENABLED || mPhase == DISPLAY_PHASE_LAYOUT_TRANSITION; } public void dumpLocked(PrintWriter pw) { pw.println("mDisplayId=" + mDisplayId); - pw.println("mIsEnabled=" + mIsEnabled); + pw.println("mPhase=" + mPhase); pw.println("mLayerStack=" + mLayerStack); pw.println("mHasContent=" + mHasContent); pw.println("mDesiredDisplayModeSpecs={" + mDesiredDisplayModeSpecs + "}"); diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index fcfa674dcc4e..4c9a2d702114 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -16,18 +16,24 @@ package com.android.server.display; +import android.annotation.NonNull; +import android.content.Context; import android.hardware.devicestate.DeviceStateManager; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.SystemProperties; import android.text.TextUtils; import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.SparseArray; -import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.view.Display; import android.view.DisplayAddress; import android.view.DisplayInfo; +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.display.LogicalDisplay.DisplayPhase; import com.android.server.display.layout.Layout; import java.io.PrintWriter; @@ -55,11 +61,20 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 3; public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4; public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5; + public static final int LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION = 6; public static final int DISPLAY_GROUP_EVENT_ADDED = 1; public static final int DISPLAY_GROUP_EVENT_CHANGED = 2; public static final int DISPLAY_GROUP_EVENT_REMOVED = 3; + private static final int TIMEOUT_STATE_TRANSITION_MILLIS = 500; + + private static final int MSG_TRANSITION_TO_PENDING_DEVICE_STATE = 1; + + private static final int UPDATE_STATE_NEW = 0; + private static final int UPDATE_STATE_TRANSITION = 1; + private static final int UPDATE_STATE_UPDATED = 2; + /** * Temporary display info, used for comparing display configurations. */ @@ -76,6 +91,11 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private final boolean mSingleDisplayDemoMode; /** + * True if the device can have more than one internal display on at a time. + */ + private final boolean mSupportsConcurrentInternalDisplays; + + /** * Map of all logical displays indexed by logical display id. * Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache. * TODO: multi-display - Move the aforementioned comment? @@ -89,13 +109,16 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private final DisplayDeviceRepository mDisplayDeviceRepo; private final DeviceStateToLayoutMap mDeviceStateToLayoutMap; private final Listener mListener; + private final DisplayManagerService.SyncRoot mSyncRoot; + private final LogicalDisplayMapperHandler mHandler; /** * Has an entry for every logical display that the rest of the system has been notified about. * Any entry in here requires us to send a {@link LOGICAL_DISPLAY_EVENT_REMOVED} event when it - * is deleted or {@link LOGICAL_DISPLAY_EVENT_CHANGED} when it is changed. + * is deleted or {@link LOGICAL_DISPLAY_EVENT_CHANGED} when it is changed. The values are any + * of the {@code UPDATE_STATE_*} constant types. */ - private final SparseBooleanArray mUpdatedLogicalDisplays = new SparseBooleanArray(); + private final SparseIntArray mUpdatedLogicalDisplays = new SparseIntArray(); /** * Keeps track of all the display groups that we already told other people about. IOW, if a @@ -119,11 +142,18 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private int mNextNonDefaultGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; private Layout mCurrentLayout = null; private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE; + private int mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE; - LogicalDisplayMapper(DisplayDeviceRepository repo, Listener listener) { + LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo, + @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, + @NonNull Handler handler) { + mSyncRoot = syncRoot; + mHandler = new LogicalDisplayMapperHandler(handler.getLooper()); mDisplayDeviceRepo = repo; mListener = listener; mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); + mSupportsConcurrentInternalDisplays = context.getResources().getBoolean( + com.android.internal.R.bool.config_supportsConcurrentInternalDisplays); mDisplayDeviceRepo.addListener(this); mDeviceStateToLayoutMap = new DeviceStateToLayoutMap(); } @@ -142,6 +172,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { if (DEBUG) { Slog.d(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked()); } + finishStateTransitionLocked(false /*force*/); updateLogicalDisplaysLocked(); break; @@ -166,7 +197,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { public LogicalDisplay getDisplayLocked(DisplayDevice device) { final int count = mLogicalDisplays.size(); for (int i = 0; i < count; i++) { - LogicalDisplay display = mLogicalDisplays.valueAt(i); + final LogicalDisplay display = mLogicalDisplays.valueAt(i); if (display.getPrimaryDisplayDeviceLocked() == device) { return display; } @@ -198,6 +229,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } } + @VisibleForTesting public int getDisplayGroupIdFromDisplayIdLocked(int displayId) { final LogicalDisplay display = getDisplayLocked(displayId); if (display == null) { @@ -225,7 +257,6 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { ipw.increaseIndent(); ipw.println("mSingleDisplayDemoMode=" + mSingleDisplayDemoMode); - ipw.println("mCurrentLayout=" + mCurrentLayout); final int logicalDisplayCount = mLogicalDisplays.size(); @@ -244,19 +275,78 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } void setDeviceStateLocked(int state) { - if (state != mDeviceState) { - resetLayoutLocked(); - mDeviceState = state; - applyLayoutLocked(); - updateLogicalDisplaysLocked(); + Slog.i(TAG, "Requesting Transition to state: " + state); + // As part of a state transition, we may need to turn off some displays temporarily so that + // the transition is smooth. Plus, on some devices, only one internal displays can be + // on at a time. We use DISPLAY_PHASE_LAYOUT_TRANSITION to mark a display that needs to be + // temporarily turned off. + if (mDeviceState != DeviceStateManager.INVALID_DEVICE_STATE) { + resetLayoutLocked(mDeviceState, state, LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION); + } + mPendingDeviceState = state; + if (areAllTransitioningDisplaysOffLocked()) { + // Nothing to wait on, we're good to go + transitionToPendingStateLocked(); + return; + } + + if (DEBUG) { + Slog.d(TAG, "Postponing transition to state: " + mPendingDeviceState); + } + // Send the transitioning phase updates to DisplayManager so that the displays can + // start turning OFF in preparation for the new layout. + updateLogicalDisplaysLocked(); + mHandler.sendEmptyMessageDelayed(MSG_TRANSITION_TO_PENDING_DEVICE_STATE, + TIMEOUT_STATE_TRANSITION_MILLIS); + } + + private boolean areAllTransitioningDisplaysOffLocked() { + final int count = mLogicalDisplays.size(); + for (int i = 0; i < count; i++) { + final LogicalDisplay display = mLogicalDisplays.valueAt(i); + if (display.getPhase() != LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) { + continue; + } + + final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); + if (device != null) { + final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); + if (info.state != Display.STATE_OFF) { + return false; + } + } + } + return true; + } + + private void transitionToPendingStateLocked() { + resetLayoutLocked(mDeviceState, mPendingDeviceState, LogicalDisplay.DISPLAY_PHASE_ENABLED); + mDeviceState = mPendingDeviceState; + mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE; + applyLayoutLocked(); + updateLogicalDisplaysLocked(); + } + + private void finishStateTransitionLocked(boolean force) { + if (mPendingDeviceState == DeviceStateManager.INVALID_DEVICE_STATE) { + return; + } + + final boolean displaysOff = areAllTransitioningDisplaysOffLocked(); + if (displaysOff || force) { + transitionToPendingStateLocked(); + mHandler.removeMessages(MSG_TRANSITION_TO_PENDING_DEVICE_STATE); + } else if (DEBUG) { + Slog.d(TAG, "Not yet ready to transition to state=" + mPendingDeviceState + + " with displays-off=" + displaysOff + " and force=" + force); } } private void handleDisplayDeviceAddedLocked(DisplayDevice device) { DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); // Internal Displays need to have additional initialization. - // TODO: b/168208162 - This initializes a default dynamic display layout for INTERNAL - // devices, which will eventually just be a fallback in case no static layout definitions + // This initializes a default dynamic display layout for INTERNAL + // devices, which is used as a fallback in case no static layout definitions // exist or cannot be loaded. if (deviceInfo.type == Display.TYPE_INTERNAL) { initializeInternalDisplayDeviceLocked(device); @@ -289,7 +379,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { display.updateLocked(mDisplayDeviceRepo); final DisplayInfo newDisplayInfo = display.getDisplayInfoLocked(); - final boolean wasPreviouslyUpdated = mUpdatedLogicalDisplays.get(displayId); + final int updateState = mUpdatedLogicalDisplays.get(displayId, UPDATE_STATE_NEW); + final boolean wasPreviouslyUpdated = updateState != UPDATE_STATE_NEW; // The display is no longer valid and needs to be removed. if (!display.isValidLocked()) { @@ -331,6 +422,10 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { assignDisplayGroupLocked(display); mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED); + } else if (updateState == UPDATE_STATE_TRANSITION) { + mLogicalDisplaysToUpdate.put(displayId, + LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION); + // Display frame rate overrides changed. } else if (!display.getPendingFrameRateOverrideUids().isEmpty()) { mLogicalDisplaysToUpdate.put( @@ -347,7 +442,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } } - mUpdatedLogicalDisplays.put(displayId, true); + mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_UPDATED); } // Go through the groups and do the same thing. We do this after displays since group @@ -376,12 +471,13 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { // Send the display and display group updates in order by message type. This is important // to ensure that addition and removal notifications happen in the right order. + sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION); sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_ADDED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REMOVED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CHANGED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED); - sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED); + sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED); sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_CHANGED); sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_REMOVED); @@ -400,7 +496,14 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } final int id = mLogicalDisplaysToUpdate.keyAt(i); - mListener.onLogicalDisplayEventLocked(getDisplayLocked(id), msg); + final LogicalDisplay display = getDisplayLocked(id); + if (DEBUG) { + final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); + final String uniqueId = device == null ? "null" : device.getUniqueId(); + Slog.d(TAG, "Sending " + displayEventToString(msg) + " for display=" + id + + " with device=" + uniqueId); + } + mListener.onLogicalDisplayEventLocked(display, msg); if (msg == LOGICAL_DISPLAY_EVENT_REMOVED) { // We wait until we sent the EVENT_REMOVED event before actually removing the // display. @@ -464,36 +567,81 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } /** - * Resets the current layout in preparation for a new layout. Layouts can specify if some - * displays should be disabled (OFF). When switching from one layout to another, we go - * through each of the displays and make sure any displays we might have disabled are - * enabled again. + * Goes through all the displays used in the layouts for the specified {@code fromState} and + * {@code toState} and applies the specified {@code phase}. When a new layout is requested, we + * put the displays that will change into a transitional phase so that they can all be turned + * OFF. Once all are confirmed OFF, then this method gets called again to reset the phase to + * normal operation. This helps to ensure that all display-OFF requests are made before + * display-ON which in turn hides any resizing-jank windows might incur when switching displays. + * + * @param fromState The state we are switching from. + * @param toState The state we are switching to. + * @param phase The new phase to apply to the displays. */ - private void resetLayoutLocked() { - final Layout layout = mDeviceStateToLayoutMap.get(mDeviceState); - for (int i = layout.size() - 1; i >= 0; i--) { - final Layout.Display displayLayout = layout.getAt(i); - final LogicalDisplay display = getDisplayLocked(displayLayout.getLogicalDisplayId()); - if (display != null) { - enableDisplayLocked(display, true); // Reset all displays back to enabled + private void resetLayoutLocked(int fromState, int toState, @DisplayPhase int phase) { + final Layout fromLayout = mDeviceStateToLayoutMap.get(fromState); + final Layout toLayout = mDeviceStateToLayoutMap.get(toState); + + final int count = mLogicalDisplays.size(); + for (int i = 0; i < count; i++) { + final LogicalDisplay logicalDisplay = mLogicalDisplays.valueAt(i); + final int displayId = logicalDisplay.getDisplayIdLocked(); + final DisplayDevice device = logicalDisplay.getPrimaryDisplayDeviceLocked(); + if (device == null) { + // If there's no device, then the logical display is due to be removed. Ignore it. + continue; + } + + // Grab the display associations this display-device has in the old layout and the + // new layout. + final DisplayAddress address = device.getDisplayDeviceInfoLocked().address; + + // Virtual displays do not have addresses. + final Layout.Display fromDisplay = + address != null ? fromLayout.getByAddress(address) : null; + final Layout.Display toDisplay = + address != null ? toLayout.getByAddress(address) : null; + + // If a layout doesn't mention a display-device at all, then the display-device defaults + // to enabled. This is why we treat null as "enabled" in the code below. + final boolean wasEnabled = fromDisplay == null || fromDisplay.isEnabled(); + final boolean willBeEnabled = toDisplay == null || toDisplay.isEnabled(); + + final boolean deviceHasNewLogicalDisplayId = fromDisplay != null && toDisplay != null + && fromDisplay.getLogicalDisplayId() != toDisplay.getLogicalDisplayId(); + + // We consider a display-device as changing/transition if + // 1) It's already marked as transitioning + // 2) It's going from enabled to disabled + // 3) It's enabled, but it's mapped to a new logical display ID. To the user this + // would look like apps moving from one screen to another since task-stacks stay + // with the logical display [ID]. + final boolean isTransitioning = + (logicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) + || (wasEnabled && !willBeEnabled) + || (wasEnabled && deviceHasNewLogicalDisplayId); + + if (isTransitioning) { + setDisplayPhase(logicalDisplay, phase); + if (phase == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) { + mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_TRANSITION); + } } } } - /** * Apply (or reapply) the currently selected display layout. */ private void applyLayoutLocked() { - final Layout layout = mDeviceStateToLayoutMap.get(mDeviceState); - mCurrentLayout = layout; - Slog.i(TAG, "Applying the display layout for device state(" + mDeviceState - + "): " + layout); + final Layout oldLayout = mCurrentLayout; + mCurrentLayout = mDeviceStateToLayoutMap.get(mDeviceState); + Slog.i(TAG, "Applying layout: " + mCurrentLayout + ", Previous layout: " + oldLayout); // Go through each of the displays in the current layout set. - final int size = layout.size(); + final int size = mCurrentLayout.size(); for (int i = 0; i < size; i++) { - final Layout.Display displayLayout = layout.getAt(i); + final Layout.Display displayLayout = mCurrentLayout.getAt(i); // If the underlying display-device we want to use for this display // doesn't exist, then skip it. This can happen at startup as display-devices @@ -521,8 +669,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { if (newDisplay != oldDisplay) { newDisplay.swapDisplaysLocked(oldDisplay); } - enableDisplayLocked(newDisplay, displayLayout.isEnabled()); + + if (!displayLayout.isEnabled()) { + setDisplayPhase(newDisplay, LogicalDisplay.DISPLAY_PHASE_DISABLED); + } } + } @@ -540,23 +692,23 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device); display.updateLocked(mDisplayDeviceRepo); mLogicalDisplays.put(displayId, display); - enableDisplayLocked(display, device != null); + setDisplayPhase(display, LogicalDisplay.DISPLAY_PHASE_ENABLED); return display; } - private void enableDisplayLocked(LogicalDisplay display, boolean isEnabled) { + private void setDisplayPhase(LogicalDisplay display, @DisplayPhase int phase) { final int displayId = display.getDisplayIdLocked(); final DisplayInfo info = display.getDisplayInfoLocked(); final boolean disallowSecondaryDisplay = mSingleDisplayDemoMode && (info.type != Display.TYPE_INTERNAL); - if (isEnabled && disallowSecondaryDisplay) { + if (phase != LogicalDisplay.DISPLAY_PHASE_DISABLED && disallowSecondaryDisplay) { Slog.i(TAG, "Not creating a logical display for a secondary display because single" + " display demo mode is enabled: " + display.getDisplayInfoLocked()); - isEnabled = false; + phase = LogicalDisplay.DISPLAY_PHASE_DISABLED; } - display.setEnabled(isEnabled); + display.setPhase(phase); } private int assignDisplayGroupIdLocked(boolean isOwnDisplayGroup) { @@ -564,14 +716,15 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } private void initializeInternalDisplayDeviceLocked(DisplayDevice device) { - // We always want to make sure that our default display layout creates a logical + // We always want to make sure that our default layout creates a logical // display for every internal display device that is found. // To that end, when we are notified of a new internal display, we add it to - // the default definition if it is not already there. - final Layout layoutSet = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT); + // the default layout definition if it is not already there. + final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT); final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); final boolean isDefault = (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0; - layoutSet.createDisplayLocked(info.address, isDefault, true /* isEnabled */); + final boolean isEnabled = isDefault || mSupportsConcurrentInternalDisplays; + layout.createDisplayLocked(info.address, isDefault, isEnabled); } private int assignLayerStackLocked(int displayId) { @@ -580,9 +733,45 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { return displayId; } + private String displayEventToString(int msg) { + switch(msg) { + case LOGICAL_DISPLAY_EVENT_ADDED: + return "added"; + case LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION: + return "transition"; + case LOGICAL_DISPLAY_EVENT_CHANGED: + return "changed"; + case LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED: + return "framerate_override"; + case LOGICAL_DISPLAY_EVENT_SWAPPED: + return "swapped"; + case LOGICAL_DISPLAY_EVENT_REMOVED: + return "removed"; + } + return null; + } + public interface Listener { void onLogicalDisplayEventLocked(LogicalDisplay display, int event); void onDisplayGroupEventLocked(int groupId, int event); void onTraversalRequested(); } + + private class LogicalDisplayMapperHandler extends Handler { + LogicalDisplayMapperHandler(Looper looper) { + super(looper, null, true /*async*/); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_TRANSITION_TO_PENDING_DEVICE_STATE: + synchronized (mSyncRoot) { + finishStateTransitionLocked(true /*force*/); + } + break; + } + } + } + } diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java index ef336674df5d..e53aec12f186 100644 --- a/services/core/java/com/android/server/display/layout/Layout.java +++ b/services/core/java/com/android/server/display/layout/Layout.java @@ -19,6 +19,7 @@ package com.android.server.display.layout; import static android.view.Display.DEFAULT_DISPLAY; import android.annotation.NonNull; +import android.annotation.Nullable; import android.util.Slog; import android.view.DisplayAddress; @@ -100,11 +101,28 @@ public class Layout { * * @return The display corresponding to the specified display ID. */ + @Nullable public Display getById(int id) { for (int i = 0; i < mDisplays.size(); i++) { - Display layout = mDisplays.get(i); - if (id == layout.getLogicalDisplayId()) { - return layout; + Display display = mDisplays.get(i); + if (id == display.getLogicalDisplayId()) { + return display; + } + } + return null; + } + + /** + * @param address The display address to check. + * + * @return The display corresponding to the specified address. + */ + @Nullable + public Display getByAddress(@NonNull DisplayAddress address) { + for (int i = 0; i < mDisplays.size(); i++) { + Display display = mDisplays.get(i); + if (address.equals(display.getAddress())) { + return display; } } return null; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java index 2bf74c95bcce..5802e53c67f1 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java @@ -232,7 +232,8 @@ public class HdmiCecMessageValidator { DEST_DIRECT); // Messages for Feature Discovery. - addValidationInfo(Constants.MESSAGE_GIVE_FEATURES, noneValidator, DEST_DIRECT); + addValidationInfo(Constants.MESSAGE_GIVE_FEATURES, noneValidator, + DEST_DIRECT | SRC_UNREGISTERED); addValidationInfo(Constants.MESSAGE_REPORT_FEATURES, new VariableLengthValidator(4, 14), DEST_BROADCAST); diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 754fa25191b0..77de187e57ca 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -422,6 +422,9 @@ public class HdmiControlService extends SystemService { // Set to true if the logical address allocation is completed. private boolean mAddressAllocated = false; + // Whether a CEC-enabled sink is connected to the playback device + private boolean mIsCecAvailable = false; + // Object that handles logging statsd atoms. // Use getAtomWriter() instead of accessing directly, to allow dependency injection for testing. private HdmiCecAtomWriter mAtomWriter = new HdmiCecAtomWriter(); @@ -2229,6 +2232,7 @@ public class HdmiControlService extends SystemService { pw.println("mProhibitMode: " + mProhibitMode); pw.println("mPowerStatus: " + mPowerStatusController.getPowerStatus()); + pw.println("mIsCecAvailable: " + mIsCecAvailable); pw.println("mCecVersion: " + mCecVersion); // System settings @@ -2450,7 +2454,7 @@ public class HdmiControlService extends SystemService { if (hdmiCecEnabled != HdmiControlManager.HDMI_CEC_CONTROL_ENABLED) { return false; } - return true; + return mIsCecAvailable; } @ServiceThreadOnly @@ -2835,24 +2839,24 @@ public class HdmiControlService extends SystemService { private void invokeHdmiControlStatusChangeListenerLocked( Collection<IHdmiControlStatusChangeListener> listeners, @HdmiControlManager.HdmiCecControl int isEnabled) { - if (listeners.isEmpty()) { - return; - } if (isEnabled == HdmiControlManager.HDMI_CEC_CONTROL_ENABLED) { queryDisplayStatus(new IHdmiControlCallback.Stub() { public void onComplete(int status) { - boolean isAvailable = true; if (status == HdmiControlManager.POWER_STATUS_UNKNOWN || status == HdmiControlManager.RESULT_EXCEPTION || status == HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE) { - isAvailable = false; + mIsCecAvailable = false; + } else { + mIsCecAvailable = true; } - invokeHdmiControlStatusChangeListenerLocked(listeners, isEnabled, isAvailable); } }); - return; + } else { + mIsCecAvailable = false; + } + if (!listeners.isEmpty()) { + invokeHdmiControlStatusChangeListenerLocked(listeners, isEnabled, mIsCecAvailable); } - invokeHdmiControlStatusChangeListenerLocked(listeners, isEnabled, false); } private void invokeHdmiControlStatusChangeListenerLocked( diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 3424821495c5..418b9695b436 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -3143,7 +3143,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public void showSoftInput(IInputMethodClient client, IBinder windowToken, int flags, - ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) { + ResultReceiver resultReceiver, @SoftInputShowHideReason int reason, + IBooleanResultCallback resultCallback) { CallbackUtils.onResult(resultCallback, () -> { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput"); int uid = Binder.getCallingUid(); @@ -3172,8 +3173,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } if (DEBUG) Slog.v(TAG, "Client requesting input be shown"); - return showCurrentInputLocked(windowToken, flags, resultReceiver, - SoftInputShowHideReason.SHOW_SOFT_INPUT); + return showCurrentInputLocked(windowToken, flags, resultReceiver, reason); } finally { Binder.restoreCallingIdentity(ident); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); @@ -3262,7 +3262,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public void hideSoftInput(IInputMethodClient client, IBinder windowToken, int flags, - ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) { + ResultReceiver resultReceiver, @SoftInputShowHideReason int reason, + IBooleanResultCallback resultCallback) { CallbackUtils.onResult(resultCallback, () -> { int uid = Binder.getCallingUid(); ImeTracing.getInstance().triggerManagerServiceDump( @@ -3296,8 +3297,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Slog.v(TAG, "Client requesting input be hidden"); return InputMethodManagerService.this.hideCurrentInputLocked(windowToken, - flags, resultReceiver, - SoftInputShowHideReason.HIDE_SOFT_INPUT); + flags, resultReceiver, reason); } finally { Binder.restoreCallingIdentity(ident); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); @@ -3326,8 +3326,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only // IMMS#InputShown indicates that the software keyboard is shown. // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested. - final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown || - (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0); + final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown + || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0); boolean res; if (shouldHideSoftInput) { final Binder hideInputToken = new Binder(); @@ -3355,68 +3355,100 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @NonNull @Override + public void reportWindowGainedFocusAsync( + boolean nextFocusHasConnection, IInputMethodClient client, IBinder windowToken, + @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, + int windowFlags, int unverifiedTargetSdkVersion) { + final int startInputReason = nextFocusHasConnection + ? StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION + : StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION; + try { + startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken, + startInputFlags, softInputMode, windowFlags, null /* attribute */, + null /* inputContext */, 0 /* missingMethods */, unverifiedTargetSdkVersion); + } catch (Throwable t) { + if (client != null) { + try { + client.throwExceptionFromSystem(t.getMessage()); + } catch (RemoteException ignore) { } + } + } + } + + @NonNull + @Override public void startInputOrWindowGainedFocus( @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext, @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion, IInputBindResultResultCallback resultCallback) { - CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () -> { - if (windowToken == null) { - Slog.e(TAG, "windowToken cannot be null."); - return InputBindResult.NULL; - } - try { - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, - "IMMS.startInputOrWindowGainedFocus"); - ImeTracing.getInstance().triggerManagerServiceDump( - "InputMethodManagerService#startInputOrWindowGainedFocus"); - final int callingUserId = UserHandle.getCallingUserId(); - final int userId; - if (attribute != null && attribute.targetInputMethodUser != null - && attribute.targetInputMethodUser.getIdentifier() != callingUserId) { - mContext.enforceCallingPermission( - Manifest.permission.INTERACT_ACROSS_USERS_FULL, - "Using EditorInfo.targetInputMethodUser requires" - + " INTERACT_ACROSS_USERS_FULL."); - userId = attribute.targetInputMethodUser.getIdentifier(); - if (!mUserManagerInternal.isUserRunning(userId)) { - // There is a chance that we hit here because of race condition. Let's just - // return an error code instead of crashing the caller process, which at - // least has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an - // important process. - Slog.e(TAG, "User #" + userId + " is not running."); - return InputBindResult.INVALID_USER; - } - } else { - userId = callingUserId; - } - final InputBindResult result; - synchronized (mMethodMap) { - final long ident = Binder.clearCallingIdentity(); - try { - result = startInputOrWindowGainedFocusInternalLocked(startInputReason, - client, windowToken, startInputFlags, softInputMode, windowFlags, - attribute, inputContext, missingMethods, unverifiedTargetSdkVersion, - userId); - } finally { - Binder.restoreCallingIdentity(ident); - } + CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () -> + startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken, + startInputFlags, softInputMode, windowFlags, attribute, inputContext, + missingMethods, unverifiedTargetSdkVersion)); + } + + @NonNull + private InputBindResult startInputOrWindowGainedFocusInternal( + @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken, + @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, + int windowFlags, @Nullable EditorInfo attribute, @Nullable IInputContext inputContext, + @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) { + if (windowToken == null) { + Slog.e(TAG, "windowToken cannot be null."); + return InputBindResult.NULL; + } + try { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, + "IMMS.startInputOrWindowGainedFocus"); + ImeTracing.getInstance().triggerManagerServiceDump( + "InputMethodManagerService#startInputOrWindowGainedFocus"); + final int callingUserId = UserHandle.getCallingUserId(); + final int userId; + if (attribute != null && attribute.targetInputMethodUser != null + && attribute.targetInputMethodUser.getIdentifier() != callingUserId) { + mContext.enforceCallingPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, + "Using EditorInfo.targetInputMethodUser requires" + + " INTERACT_ACROSS_USERS_FULL."); + userId = attribute.targetInputMethodUser.getIdentifier(); + if (!mUserManagerInternal.isUserRunning(userId)) { + // There is a chance that we hit here because of race condition. Let's just + // return an error code instead of crashing the caller process, which at + // least has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an + // important process. + Slog.e(TAG, "User #" + userId + " is not running."); + return InputBindResult.INVALID_USER; } - if (result == null) { - // This must never happen, but just in case. - Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason=" - + InputMethodDebug.startInputReasonToString(startInputReason) - + " windowFlags=#" + Integer.toHexString(windowFlags) - + " editorInfo=" + attribute); - return InputBindResult.NULL; + } else { + userId = callingUserId; + } + final InputBindResult result; + synchronized (mMethodMap) { + final long ident = Binder.clearCallingIdentity(); + try { + result = startInputOrWindowGainedFocusInternalLocked(startInputReason, + client, windowToken, startInputFlags, softInputMode, windowFlags, + attribute, inputContext, missingMethods, unverifiedTargetSdkVersion, + userId); + } finally { + Binder.restoreCallingIdentity(ident); } - - return result; - } finally { - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } - }); + if (result == null) { + // This must never happen, but just in case. + Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason=" + + InputMethodDebug.startInputReasonToString(startInputReason) + + " windowFlags=#" + Integer.toHexString(windowFlags) + + " editorInfo=" + attribute); + return InputBindResult.NULL; + } + + return result; + } finally { + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + } } @NonNull @@ -4444,7 +4476,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub ((IInputMethod) args.arg1).showSoftInput( (IBinder) args.arg3, msg.arg1, (ResultReceiver) args.arg2); mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry( - mCurClient, mCurAttribute, + mCurFocusedWindowClient, mCurAttribute, mWindowManagerInternal.getWindowName(mCurFocusedWindow), mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode, mWindowManagerInternal.getWindowName( @@ -4467,7 +4499,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub ((IInputMethod)args.arg1).hideSoftInput( (IBinder) args.arg3, 0, (ResultReceiver)args.arg2); mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry( - mCurClient, mCurAttribute, + mCurFocusedWindowClient, mCurAttribute, mWindowManagerInternal.getWindowName(mCurFocusedWindow), mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode, mWindowManagerInternal.getWindowName( @@ -6057,10 +6089,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @BinderThread @Override - public void updateStatusIcon(String packageName, @DrawableRes int iconId, - IVoidResultCallback resultCallback) { - CallbackUtils.onResult(resultCallback, - () -> mImms.updateStatusIcon(mToken, packageName, iconId)); + public void updateStatusIconAsync(String packageName, @DrawableRes int iconId) { + mImms.updateStatusIcon(mToken, packageName, iconId); } @BinderThread @@ -6087,16 +6117,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @BinderThread @Override - public void notifyUserAction(IVoidResultCallback resultCallback) { - CallbackUtils.onResult(resultCallback, () -> mImms.notifyUserAction(mToken)); + public void notifyUserActionAsync() { + mImms.notifyUserAction(mToken); } @BinderThread @Override - public void applyImeVisibility(IBinder windowToken, boolean setVisible, - IVoidResultCallback resultCallback) { - CallbackUtils.onResult(resultCallback, - () -> mImms.applyImeVisibility(mToken, windowToken, setVisible)); + public void applyImeVisibilityAsync(IBinder windowToken, boolean setVisible) { + mImms.applyImeVisibility(mToken, windowToken, setVisible); } } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java index e25b03481934..403187bb53ff 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java @@ -221,7 +221,6 @@ public class InputMethodMenuController { */ @VisibleForTesting public Context getSettingsContext(int displayId) { - // TODO(b/178462039): Cover the case when IME is moved to another ImeContainer. if (mSettingsContext == null || mSettingsContext.getDisplayId() != displayId) { final Context systemUiContext = ActivityThread.currentActivityThread() .createSystemUiContext(displayId); diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index fcaf6d8fe400..69f293d056cb 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -1521,8 +1521,8 @@ public final class MultiClientInputMethodManagerService { @BinderThread @Override public void showSoftInput( - IInputMethodClient client, IBinder token, int flags, - ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) { + IInputMethodClient client, IBinder token, int flags, ResultReceiver resultReceiver, + @SoftInputShowHideReason int reason, IBooleanResultCallback resultCallback) { CallbackUtils.onResult(resultCallback, () -> showSoftInputInternal(client, token, flags, resultReceiver)); } @@ -1577,7 +1577,8 @@ public final class MultiClientInputMethodManagerService { @Override public void hideSoftInput( IInputMethodClient client, IBinder windowToken, int flags, - ResultReceiver resultReceiver, IBooleanResultCallback resultCallback) { + ResultReceiver resultReceiver, @SoftInputShowHideReason int reason, + IBooleanResultCallback resultCallback) { CallbackUtils.onResult(resultCallback, () -> hideSoftInputInternal(client, windowToken, flags, resultReceiver)); @@ -1627,6 +1628,33 @@ public final class MultiClientInputMethodManagerService { @BinderThread @Override + public void reportWindowGainedFocusAsync( + boolean nextFocusHasConnection, + @Nullable IInputMethodClient client, + @Nullable IBinder windowToken, + @StartInputFlags int startInputFlags, + @SoftInputModeFlags int softInputMode, + int windowFlags, + int unverifiedTargetSdkVersion) { + final int startInputReason = nextFocusHasConnection + ? StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION + : StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION; + try { + startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken, + startInputFlags, softInputMode, windowFlags, null /* editorInfo */, + null /* inputContext */, 0 /* missingMethods */, + unverifiedTargetSdkVersion); + } catch (Throwable t) { + if (client != null) { + try { + client.throwExceptionFromSystem(t.getMessage()); + } catch (RemoteException ignore) { } + } + } + } + + @BinderThread + @Override public void startInputOrWindowGainedFocus( @StartInputReason int startInputReason, @Nullable IInputMethodClient client, @@ -1641,8 +1669,8 @@ public final class MultiClientInputMethodManagerService { IInputBindResultResultCallback resultCallback) { CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () -> startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken, - startInputFlags, softInputMode, windowFlags, editorInfo, inputContext, - missingMethods, unverifiedTargetSdkVersion)); + startInputFlags, softInputMode, windowFlags, editorInfo, inputContext, + missingMethods, unverifiedTargetSdkVersion)); } @BinderThread diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index d110839a2204..5b03989f5248 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -30,6 +30,8 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSW import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; +import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_DECRYPT; +import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT; import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE; @@ -99,6 +101,7 @@ import android.security.keystore.recovery.KeyChainProtectionParams; import android.security.keystore.recovery.KeyChainSnapshot; import android.security.keystore.recovery.RecoveryCertPath; import android.security.keystore.recovery.WrappedApplicationKey; +import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; import android.security.keystore2.AndroidKeyStoreProvider; import android.service.gatekeeper.GateKeeperResponse; import android.service.gatekeeper.IGateKeeperService; @@ -155,6 +158,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -226,6 +230,7 @@ public class LockSettingsService extends ILockSettings.Stub { private final SyntheticPasswordManager mSpManager; private final KeyStore mKeyStore; + private final java.security.KeyStore mJavaKeyStore; private final RecoverableKeyStoreManager mRecoverableKeyStoreManager; private ManagedProfilePasswordCache mManagedProfilePasswordCache; @@ -535,16 +540,22 @@ public class LockSettingsService extends ILockSettings.Stub { return Settings.Secure.getIntForUser(contentResolver, keyName, defaultValue, userId); } - public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache() { + public java.security.KeyStore getJavaKeyStore() { try { java.security.KeyStore ks = java.security.KeyStore.getInstance( SyntheticPasswordCrypto.androidKeystoreProviderName()); - ks.load(null); - return new ManagedProfilePasswordCache(ks, getUserManager()); + ks.load(new AndroidKeyStoreLoadStoreParameter( + SyntheticPasswordCrypto.keyNamespace())); + return ks; } catch (Exception e) { throw new IllegalStateException("Cannot load keystore", e); } } + + public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache( + java.security.KeyStore ks) { + return new ManagedProfilePasswordCache(ks, getUserManager()); + } } public LockSettingsService(Context context) { @@ -556,6 +567,7 @@ public class LockSettingsService extends ILockSettings.Stub { mInjector = injector; mContext = injector.getContext(); mKeyStore = injector.getKeyStore(); + mJavaKeyStore = injector.getJavaKeyStore(); mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(); mHandler = injector.getHandler(injector.getServiceThread()); mStrongAuth = injector.getStrongAuth(); @@ -580,7 +592,7 @@ public class LockSettingsService extends ILockSettings.Stub { mRandom = new SecureRandom(); mSpManager = injector.getSyntheticPasswordManager(mStorage); - mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache(); + mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache(mJavaKeyStore); mBiometricDeferredQueue = new BiometricDeferredQueue(mContext, mSpManager, mHandler); mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(), @@ -955,6 +967,21 @@ public class LockSettingsService extends ILockSettings.Stub { setString("migrated_wear_lockscreen_disabled", "true", 0); Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices"); } + + if (getString("migrated_keystore_namespace", null, 0) == null) { + boolean success = true; + synchronized (mSpManager) { + success &= mSpManager.migrateKeyNamespace(); + } + success &= migrateProfileLockKeys(); + if (success) { + setString("migrated_keystore_namespace", "true", 0); + Slog.i(TAG, "Migrated keys to LSS namespace"); + } else { + Slog.w(TAG, "Failed to migrate keys to LSS namespace"); + } + } + } private void migrateOldDataAfterSystemReady() { @@ -995,6 +1022,22 @@ public class LockSettingsService extends ILockSettings.Stub { } } + private boolean migrateProfileLockKeys() { + boolean success = true; + final List<UserInfo> users = mUserManager.getUsers(); + final int userCount = users.size(); + for (int i = 0; i < userCount; i++) { + UserInfo user = users.get(i); + if (user.isManagedProfile() && !getSeparateProfileChallengeEnabledInternal(user.id)) { + success &= SyntheticPasswordCrypto.migrateLockSettingsKey( + PROFILE_KEY_NAME_ENCRYPT + user.id); + success &= SyntheticPasswordCrypto.migrateLockSettingsKey( + PROFILE_KEY_NAME_DECRYPT + user.id); + } + } + return success; + } + /** * Returns the lowest password quality that still presents the same UI for entering it. * @@ -1268,7 +1311,7 @@ public class LockSettingsService extends ILockSettings.Stub { private void unlockKeystore(byte[] password, int userHandle) { if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle); - Authorization.onLockScreenEvent(false, userHandle, password); + Authorization.onLockScreenEvent(false, userHandle, password, null); } @VisibleForTesting /** Note: this method is overridden in unit tests */ @@ -1286,11 +1329,8 @@ public class LockSettingsService extends ILockSettings.Stub { byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE, storedData.length); byte[] decryptionResult; - java.security.KeyStore keyStore = java.security.KeyStore.getInstance( - SyntheticPasswordCrypto.androidKeystoreProviderName()); - keyStore.load(null); - SecretKey decryptionKey = (SecretKey) keyStore.getKey( - LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null); + SecretKey decryptionKey = (SecretKey) mJavaKeyStore.getKey( + PROFILE_KEY_NAME_DECRYPT + userId, null); Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE); @@ -1880,30 +1920,26 @@ public class LockSettingsService extends ILockSettings.Stub { KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES); keyGenerator.init(new SecureRandom()); SecretKey secretKey = keyGenerator.generateKey(); - java.security.KeyStore keyStore = java.security.KeyStore.getInstance( - SyntheticPasswordCrypto.androidKeystoreProviderName()); - keyStore.load(null); try { - keyStore.setEntry( - LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, + mJavaKeyStore.setEntry( + PROFILE_KEY_NAME_ENCRYPT + userId, new java.security.KeyStore.SecretKeyEntry(secretKey), new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .build()); - keyStore.setEntry( - LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, + mJavaKeyStore.setEntry( + PROFILE_KEY_NAME_DECRYPT + userId, new java.security.KeyStore.SecretKeyEntry(secretKey), new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setUserAuthenticationRequired(true) .setUserAuthenticationValidityDurationSeconds(30) - .setCriticalToDeviceEncryption(true) .build()); // Key imported, obtain a reference to it. - SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey( - LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null); + SecretKey keyStoreEncryptionKey = (SecretKey) mJavaKeyStore.getKey( + PROFILE_KEY_NAME_ENCRYPT + userId, null); Cipher cipher = Cipher.getInstance( KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE); @@ -1912,10 +1948,10 @@ public class LockSettingsService extends ILockSettings.Stub { iv = cipher.getIV(); } finally { // The original key can now be discarded. - keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId); + mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + userId); } - } catch (CertificateException | UnrecoverableKeyException - | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException + } catch (UnrecoverableKeyException + | BadPaddingException | IllegalBlockSizeException | KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) { throw new IllegalStateException("Failed to encrypt key", e); } @@ -2460,13 +2496,9 @@ public class LockSettingsService extends ILockSettings.Stub { private void removeKeystoreProfileKey(int targetUserId) { Slog.i(TAG, "Remove keystore profile key for user: " + targetUserId); try { - java.security.KeyStore keyStore = java.security.KeyStore.getInstance( - SyntheticPasswordCrypto.androidKeystoreProviderName()); - keyStore.load(null); - keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId); - keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId); - } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException - | IOException e) { + mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + targetUserId); + mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_DECRYPT + targetUserId); + } catch (KeyStoreException e) { // We have tried our best to remove all keys Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e); } @@ -3420,6 +3452,12 @@ public class LockSettingsService extends ILockSettings.Stub { pw.println(); pw.decreaseIndent(); + pw.println("Keys in namespace:"); + pw.increaseIndent(); + dumpKeystoreKeys(pw); + pw.println(); + pw.decreaseIndent(); + pw.println("Storage:"); pw.increaseIndent(); mStorage.dump(pw); @@ -3441,6 +3479,18 @@ public class LockSettingsService extends ILockSettings.Stub { pw.println("PasswordHandleCount: " + mGatekeeperPasswords.size()); } + private void dumpKeystoreKeys(IndentingPrintWriter pw) { + try { + final Enumeration<String> aliases = mJavaKeyStore.aliases(); + while (aliases.hasMoreElements()) { + pw.println(aliases.nextElement()); + } + } catch (KeyStoreException e) { + pw.println("Unable to get keys: " + e.toString()); + Slog.d(TAG, "Dump error", e); + } + } + /** * Cryptographically disable escrow token support for the current user, if the user is not * managed (either user has a profile owner, or if device is managed). Do not disable diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java index 6a5c2d89a4e2..a73c8e0c914a 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java @@ -311,7 +311,7 @@ class LockSettingsShellCommand extends ShellCommand { PasswordMetrics metrics = new PasswordMetrics( credential.isPattern() ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_NONE); errors = PasswordMetrics.validatePasswordMetrics( - requiredMetrics, requiredComplexity, false /* isPin */, metrics); + requiredMetrics, requiredComplexity, metrics); } if (!errors.isEmpty()) { getOutPrintWriter().println( diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java index fa477c8fd35a..672c3f739413 100644 --- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java +++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java @@ -23,7 +23,6 @@ import android.os.UserManager; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.security.keystore.UserNotAuthenticatedException; -import android.security.keystore2.AndroidKeyStoreSpi; import android.util.Slog; import android.util.SparseArray; @@ -95,11 +94,12 @@ public class ManagedProfilePasswordCache { SecretKey key; try { generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, - AndroidKeyStoreSpi.NAME); + mKeyStore.getProvider()); generator.init(new KeyGenParameterSpec.Builder( keyName, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setKeySize(KEY_LENGTH) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) + .setNamespace(SyntheticPasswordCrypto.keyNamespace()) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) // Generate auth-bound key to user 0 (since we the caller is user 0) .setUserAuthenticationRequired(true) diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index 90694d0a5f64..3f2b8fffcc54 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -31,6 +31,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.Handler; import android.os.SystemClock; @@ -224,6 +225,12 @@ class RebootEscrowManager { } public boolean serverBasedResumeOnReboot() { + // Always use the server based RoR if the HAL isn't installed on device. + if (!mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_REBOOT_ESCROW)) { + return true; + } + return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA, "server_based_ror_enabled", false); } @@ -374,6 +381,7 @@ class RebootEscrowManager { try { escrowKey = getAndClearRebootEscrowKey(kk); } catch (IOException e) { + Slog.i(TAG, "Failed to load escrow key, scheduling retry.", e); scheduleLoadRebootEscrowDataOrFail(retryHandler, attemptNumber + 1, users, rebootEscrowUsers); return; diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java index 35e6489debcf..3386408f32cc 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java @@ -16,8 +16,12 @@ package com.android.server.locksettings; +import android.security.AndroidKeyStoreMaintenance; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; +import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; +import android.system.keystore2.Domain; +import android.system.keystore2.KeyDescriptor; import android.util.Slog; import java.io.ByteArrayOutputStream; @@ -125,9 +129,7 @@ public class SyntheticPasswordCrypto { public static byte[] decryptBlobV1(String keyAlias, byte[] blob, byte[] applicationId) { try { - KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); - keyStore.load(null); - + KeyStore keyStore = getKeyStore(); SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null); if (decryptionKey == null) { throw new IllegalStateException("SP key is missing: " + keyAlias); @@ -144,10 +146,20 @@ public class SyntheticPasswordCrypto { return "AndroidKeyStore"; } + static int keyNamespace() { + return KeyProperties.NAMESPACE_LOCKSETTINGS; + } + + private static KeyStore getKeyStore() + throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException { + KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); + keyStore.load(new AndroidKeyStoreLoadStoreParameter(keyNamespace())); + return keyStore; + } + public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) { try { - KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); - keyStore.load(null); + final KeyStore keyStore = getKeyStore(); SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null); if (decryptionKey == null) { @@ -170,8 +182,7 @@ public class SyntheticPasswordCrypto { KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES); keyGenerator.init(AES_KEY_LENGTH * 8, new SecureRandom()); SecretKey secretKey = keyGenerator.generateKey(); - KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); - keyStore.load(null); + final KeyStore keyStore = getKeyStore(); KeyProtection.Builder builder = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) @@ -200,8 +211,7 @@ public class SyntheticPasswordCrypto { public static void destroyBlobKey(String keyAlias) { KeyStore keyStore; try { - keyStore = KeyStore.getInstance(androidKeystoreProviderName()); - keyStore.load(null); + keyStore = getKeyStore(); keyStore.deleteEntry(keyAlias); Slog.i(TAG, "SP key deleted: " + keyAlias); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException @@ -229,4 +239,32 @@ public class SyntheticPasswordCrypto { throw new IllegalStateException("NoSuchAlgorithmException for SHA-512", e); } } + + static boolean migrateLockSettingsKey(String alias) { + final KeyDescriptor legacyKey = new KeyDescriptor(); + legacyKey.domain = Domain.APP; + legacyKey.nspace = KeyProperties.NAMESPACE_APPLICATION; + legacyKey.alias = alias; + + final KeyDescriptor newKey = new KeyDescriptor(); + newKey.domain = Domain.SELINUX; + newKey.nspace = SyntheticPasswordCrypto.keyNamespace(); + newKey.alias = alias; + Slog.i(TAG, "Migrating key " + alias); + int err = AndroidKeyStoreMaintenance.migrateKeyNamespace(legacyKey, newKey); + if (err == 0) { + return true; + } else if (err == AndroidKeyStoreMaintenance.KEY_NOT_FOUND) { + Slog.i(TAG, "Key does not exist"); + // Treat this as a success so we don't migrate again. + return true; + } else if (err == AndroidKeyStoreMaintenance.INVALID_ARGUMENT) { + Slog.i(TAG, "Key already exists"); + // Treat this as a success so we don't migrate again. + return true; + } else { + Slog.e(TAG, String.format("Failed to migrate key: %d", err)); + return false; + } + } } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index a5763aee6336..601a5727e545 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -522,7 +522,7 @@ public class SyntheticPasswordManager { public void removeUser(int userId) { for (long handle : mStorage.listSyntheticPasswordHandlesForUser(SP_BLOB_NAME, userId)) { destroyWeaverSlot(handle, userId); - destroySPBlobKey(getHandleName(handle)); + destroySPBlobKey(getKeyName(handle)); } } @@ -958,7 +958,7 @@ public class SyntheticPasswordManager { } else { secret = authToken.getSyntheticPassword(); } - byte[] content = createSPBlob(getHandleName(handle), secret, applicationId, sid); + byte[] content = createSPBlob(getKeyName(handle), secret, applicationId, sid); byte[] blob = new byte[content.length + 1 + 1]; /* * We can upgrade from v1 to v2 because that's just a change in the way that @@ -1141,10 +1141,10 @@ public class SyntheticPasswordManager { } final byte[] secret; if (version == SYNTHETIC_PASSWORD_VERSION_V1) { - secret = SyntheticPasswordCrypto.decryptBlobV1(getHandleName(handle), + secret = SyntheticPasswordCrypto.decryptBlobV1(getKeyName(handle), Arrays.copyOfRange(blob, 2, blob.length), applicationId); } else { - secret = decryptSPBlob(getHandleName(handle), + secret = decryptSPBlob(getKeyName(handle), Arrays.copyOfRange(blob, 2, blob.length), applicationId); } if (secret == null) { @@ -1247,7 +1247,7 @@ public class SyntheticPasswordManager { private void destroySyntheticPassword(long handle, int userId) { destroyState(SP_BLOB_NAME, handle, userId); - destroySPBlobKey(getHandleName(handle)); + destroySPBlobKey(getKeyName(handle)); if (hasState(WEAVER_SLOT_NAME, handle, userId)) { destroyWeaverSlot(handle, userId); } @@ -1363,7 +1363,7 @@ public class SyntheticPasswordManager { } } - private String getHandleName(long handle) { + private String getKeyName(long handle) { return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle); } @@ -1424,4 +1424,19 @@ public class SyntheticPasswordManager { } return hexBytes; } + + /** + * Migrate all existing SP keystore keys from uid 1000 app domain to LSS selinux domain + */ + public boolean migrateKeyNamespace() { + boolean success = true; + final Map<Integer, List<Long>> allHandles = + mStorage.listSyntheticPasswordHandlesForAllUsers(SP_BLOB_NAME); + for (List<Long> userHandles : allHandles.values()) { + for (long handle : userHandles) { + success &= SyntheticPasswordCrypto.migrateLockSettingsKey(getKeyName(handle)); + } + } + return success; + } } diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index e7c0a50163da..431b00914f02 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -382,8 +382,8 @@ public class NetworkStatsFactory { // Migrate data usage over a VPN to the TUN network. for (UnderlyingNetworkInfo info : vpnArray) { - delta.migrateTun(info.getOwnerUid(), info.getIface(), - info.getUnderlyingIfaces()); + delta.migrateTun(info.getOwnerUid(), info.getInterface(), + info.getUnderlyingInterfaces()); // Filter out debug entries as that may lead to over counting. delta.filterDebugEntries(); } diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java index 29b5e81447f8..78219bcb9011 100644 --- a/services/core/java/com/android/server/notification/NotificationComparator.java +++ b/services/core/java/com/android/server/notification/NotificationComparator.java @@ -147,15 +147,16 @@ public class NotificationComparator } private boolean isImportantOngoing(NotificationRecord record) { - if (!isOngoing(record)) { + if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) { return false; } - - if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) { + if (isCallStyle(record)) { + return true; + } + if (!isOngoing(record)) { return false; } - - return isCall(record) || isMediaNotification(record); + return isCallCategory(record) || isMediaNotification(record); } protected boolean isImportantPeople(NotificationRecord record) { @@ -181,11 +182,16 @@ public class NotificationComparator return record.getNotification().hasMediaSession(); } - private boolean isCall(NotificationRecord record) { + private boolean isCallCategory(NotificationRecord record) { return record.isCategory(Notification.CATEGORY_CALL) && isDefaultPhoneApp(record.getSbn().getPackageName()); } + private boolean isCallStyle(NotificationRecord record) { + return "android.app.Notification$CallStyle".equals( + record.getNotification().extras.getString(Notification.EXTRA_TEMPLATE)); + } + private boolean isDefaultPhoneApp(String pkg) { if (mDefaultPhoneApp == null) { final TelecomManager telecomm = diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 1c50d41e45d3..08a7d9e38d96 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -695,14 +695,15 @@ public class NotificationManagerService extends SystemService { // Remove notifications with the specified user & channel ID. public void removeChannelNotifications(String pkg, @UserIdInt int userId, String channelId) { - for (int i = 0; i < mBuffer.size(); i++) { - final Pair<StatusBarNotification, Integer> pair = mBuffer.get(i); + Iterator<Pair<StatusBarNotification, Integer>> bufferIter = mBuffer.iterator(); + while (bufferIter.hasNext()) { + final Pair<StatusBarNotification, Integer> pair = bufferIter.next(); if (pair.first != null && userId == pair.first.getNormalizedUserId() && pkg != null && pkg.equals(pair.first.getPackageName()) && pair.first.getNotification() != null && Objects.equals(channelId, pair.first.getNotification().getChannelId())) { - mBuffer.remove(i); + bufferIter.remove(); } } } @@ -3022,18 +3023,21 @@ public class NotificationManagerService extends SystemService { getRealUserId(r.getSbn().getUserId())); Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryAddItem"); try { - mHistoryManager.addNotification(new HistoricalNotification.Builder() - .setPackage(r.getSbn().getPackageName()) - .setUid(r.getSbn().getUid()) - .setUserId(r.getSbn().getNormalizedUserId()) - .setChannelId(r.getChannel().getId()) - .setChannelName(r.getChannel().getName().toString()) - .setPostedTimeMs(System.currentTimeMillis()) - .setTitle(getHistoryTitle(r.getNotification())) - .setText(getHistoryText( - r.getSbn().getPackageContext(getContext()), r.getNotification())) - .setIcon(r.getNotification().getSmallIcon()) - .build()); + if (r.getNotification().getSmallIcon() != null) { + mHistoryManager.addNotification(new HistoricalNotification.Builder() + .setPackage(r.getSbn().getPackageName()) + .setUid(r.getSbn().getUid()) + .setUserId(r.getSbn().getNormalizedUserId()) + .setChannelId(r.getChannel().getId()) + .setChannelName(r.getChannel().getName().toString()) + .setPostedTimeMs(System.currentTimeMillis()) + .setTitle(getHistoryTitle(r.getNotification())) + .setText(getHistoryText( + r.getSbn().getPackageContext(getContext()), + r.getNotification())) + .setIcon(r.getNotification().getSmallIcon()) + .build()); + } } finally { Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); } @@ -6570,6 +6574,17 @@ public class NotificationManagerService extends SystemService { } } + if ("android.app.Notification$CallStyle".equals( + n.extras.getString(Notification.EXTRA_TEMPLATE))) { + boolean isForegroundService = (n.flags & FLAG_FOREGROUND_SERVICE) != 0; + boolean hasFullScreenIntent = n.fullScreenIntent != null; + if (!isForegroundService && !hasFullScreenIntent) { + throw new IllegalArgumentException(r.getKey() + " Not posted." + + " CallStyle notifications must either be for a foreground Service or" + + " use a fullScreenIntent."); + } + } + // snoozed apps if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) { MetricsLogger.action(r.getLogMaker() diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index f31d1da84c35..0f6e3842388e 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -25,6 +25,7 @@ import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; import android.apex.ApexSessionParams; +import android.apex.CompressedApexInfoList; import android.apex.IApexService; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; @@ -374,6 +375,21 @@ public abstract class ApexManager { public abstract void markBootCompleted(); /** + * Estimate how much storage space is needed on /data/ for decompressing apexes + * @param infoList List of apexes that are compressed in target build. + * @return Size, in bytes, the amount of space needed on /data/ + */ + public abstract long calculateSizeForCompressedApex(CompressedApexInfoList infoList) + throws RemoteException; + + /** + * Reserve space on /data so that apexes can be decompressed after OTA + * @param infoList List of apexes that are compressed in target build. + */ + public abstract void reserveSpaceForCompressedApex(CompressedApexInfoList infoList) + throws RemoteException; + + /** * Dumps various state information to the provided {@link PrintWriter} object. * * @param pw the {@link PrintWriter} object to send information to. @@ -946,6 +962,18 @@ public abstract class ApexManager { } } + @Override + public long calculateSizeForCompressedApex(CompressedApexInfoList infoList) + throws RemoteException { + return waitForApexService().calculateSizeForCompressedApex(infoList); + } + + @Override + public void reserveSpaceForCompressedApex(CompressedApexInfoList infoList) + throws RemoteException { + waitForApexService().reserveSpaceForCompressedApex(infoList); + } + /** * Dump information about the packages contained in a particular cache * @param packagesCache the cache to print information about. @@ -1203,6 +1231,16 @@ public abstract class ApexManager { } @Override + public long calculateSizeForCompressedApex(CompressedApexInfoList infoList) { + throw new UnsupportedOperationException(); + } + + @Override + public void reserveSpaceForCompressedApex(CompressedApexInfoList infoList) { + throw new UnsupportedOperationException(); + } + + @Override void dump(PrintWriter pw, String packageName) { // No-op } diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 4f527f26cbb3..cd352b5fb1be 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -35,6 +35,7 @@ import android.content.pm.parsing.component.ParsedInstrumentation; import android.content.pm.parsing.component.ParsedIntentInfo; import android.content.pm.parsing.component.ParsedMainComponent; import android.content.pm.parsing.component.ParsedProvider; +import android.os.Binder; import android.os.Process; import android.os.Trace; import android.os.UserHandle; @@ -51,6 +52,7 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.function.QuadFunction; import com.android.server.FgThread; import com.android.server.compat.CompatChange; import com.android.server.om.OverlayReferenceMapper; @@ -69,7 +71,6 @@ import java.util.Objects; import java.util.Set; import java.util.StringTokenizer; import java.util.concurrent.Executor; -import java.util.function.Function; /** * The entity responsible for filtering visibility between apps based on declarations in their @@ -1447,14 +1448,20 @@ public class AppsFilter implements Watchable, Snappable { public void dumpQueries( PrintWriter pw, @Nullable Integer filteringAppId, DumpState dumpState, int[] users, - Function<Integer, String[]> getPackagesForUid) { + QuadFunction<Integer, Integer, Integer, Boolean, String[]> getPackagesForUid) { final SparseArray<String> cache = new SparseArray<>(); ToString<Integer> expandPackages = input -> { String cachedValue = cache.get(input); if (cachedValue == null) { - final String[] packagesForUid = getPackagesForUid.apply(input); + final int callingUid = Binder.getCallingUid(); + final int appId = UserHandle.getAppId(input); + String[] packagesForUid = null; + for (int i = 0, size = users.length; packagesForUid == null && i < size; i++) { + packagesForUid = getPackagesForUid.apply(callingUid, users[i], appId, + false /*isCallerInstantApp*/); + } if (packagesForUid == null) { - cachedValue = "[unknown app id " + input + "]"; + cachedValue = "[app id " + input + " not installed]"; } else { cachedValue = packagesForUid.length == 1 ? packagesForUid[0] : "[" + TextUtils.join(",", packagesForUid) + "]"; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 6b7e729671c5..a799ce20f5c7 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -883,6 +883,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return isDataLoaderInstallation() && params.dataLoaderParams.getType() == INCREMENTAL; } + private boolean isSystemDataLoaderInstallation() { + if (!isDataLoaderInstallation()) { + return false; + } + return SYSTEM_DATA_LOADER_PACKAGE.equals( + this.params.dataLoaderParams.getComponentName().getPackageName()); + } + /** * @return {@code true} iff the installing is app an device owner or affiliated profile owner. */ @@ -1058,9 +1066,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "DataLoader installation of APEX modules is not allowed."); } - boolean systemDataLoader = SYSTEM_DATA_LOADER_PACKAGE.equals( - this.params.dataLoaderParams.getComponentName().getPackageName()); - if (systemDataLoader && mContext.checkCallingOrSelfPermission( + if (isSystemDataLoaderInstallation() && mContext.checkCallingOrSelfPermission( Manifest.permission.USE_SYSTEM_DATA_LOADERS) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("You need the " @@ -2107,6 +2113,23 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { dispatchSessionFinished(error, detailedMessage, null); } + private void onSystemDataLoaderUnrecoverable() { + final PackageManagerService packageManagerService = mPm; + final String packageName = mPackageName; + if (TextUtils.isEmpty(packageName)) { + // The package has not been installed. + return; + } + mHandler.post(() -> { + if (packageManagerService.deletePackageX(packageName, + PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM, + PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/) + != PackageManager.DELETE_SUCCEEDED) { + Slog.e(TAG, "Failed to uninstall package with failed dataloader: " + packageName); + } + }); + } + /** * If session should be sealed, then it's sealed to prevent further modification. * If the session can't be sealed then it's destroyed. @@ -3740,6 +3763,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final DataLoaderParams params = this.params.dataLoaderParams; final boolean manualStartAndDestroy = !isIncrementalInstallation(); + final boolean systemDataLoader = isSystemDataLoaderInstallation(); final IDataLoaderStatusListener statusListener = new IDataLoaderStatusListener.Stub() { @Override public void onStatusChanged(int dataLoaderId, int status) { @@ -3751,10 +3775,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (mDestroyed || mDataLoaderFinished) { - // No need to worry about post installation + switch (status) { + case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE: + if (systemDataLoader) { + onSystemDataLoaderUnrecoverable(); + } + return; + } return; } - try { IDataLoader dataLoader = dataLoaderManager.getDataLoader(dataLoaderId); if (dataLoader == null) { @@ -3848,14 +3877,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS; healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS; - final boolean systemDataLoader = SYSTEM_DATA_LOADER_PACKAGE.equals( - params.getComponentName().getPackageName()); - final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() { @Override public void onHealthStatus(int storageId, int status) { if (mDestroyed || mDataLoaderFinished) { - // No need to worry about post installation return; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index d2cbcf0598fc..9a3fe82f2d0f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -4619,7 +4619,7 @@ public class PackageManagerService extends IPackageManager.Stub Integer filteringAppId = setting == null ? null : setting.appId; mAppsFilter.dumpQueries( pw, filteringAppId, dumpState, mUserManager.getUserIds(), - this::getPackagesForUid); + this::getPackagesForUidInternalBody); break; } @@ -4883,6 +4883,11 @@ public class PackageManagerService extends IPackageManager.Stub return super.filterAppAccess(packageName, callingUid, userId); } } + public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) { + synchronized (mLock) { + super.dump(type, fd, pw, dumpState); + } + } } @@ -21627,7 +21632,8 @@ public class PackageManagerService extends IPackageManager.Stub null /*disabledComponents*/, PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.UNINSTALL_REASON_UNKNOWN, - null /*harmfulAppWarning*/); + null /*harmfulAppWarning*/, + null /*splashScreenTheme*/); } mSettings.writeKernelMappingLPr(ps); } @@ -27701,6 +27707,23 @@ public class PackageManagerService extends IPackageManager.Stub return mSettings.getPackageLPr(packageName).getMimeGroup(mimeGroup); } + @Override + public void setSplashScreenTheme(@NonNull String packageName, @Nullable String themeId, + int userId) { + int callingUid = Binder.getCallingUid(); + PackageSetting packageSetting = getPackageSettingForUser(packageName, callingUid, userId); + if (packageSetting != null) { + packageSetting.setSplashScreenTheme(userId, themeId); + } + } + + @Override + public String getSplashScreenTheme(@NonNull String packageName, int userId) { + int callingUid = Binder.getCallingUid(); + PackageSetting packageSetting = getPackageSettingForUser(packageName, callingUid, userId); + return packageSetting != null ? packageSetting.getSplashScreenTheme(userId) : null; + } + /** * Temporary method that wraps mSettings.writeLPr() and calls mPermissionManager's * writeLegacyPermissionsTEMP() beforehand. diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 19b56b75d712..731d41c38f79 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -493,7 +493,8 @@ public abstract class PackageSettingBase extends SettingBase { ArrayMap<String, PackageUserState.SuspendParams> suspendParams, boolean instantApp, boolean virtualPreload, String lastDisableAppCaller, ArraySet<String> enabledComponents, ArraySet<String> disabledComponents, - int installReason, int uninstallReason, String harmfulAppWarning) { + int installReason, int uninstallReason, String harmfulAppWarning, + String splashScreenTheme) { PackageUserState state = modifyUserState(userId); state.ceDataInode = ceDataInode; state.enabled = enabled; @@ -512,6 +513,7 @@ public abstract class PackageSettingBase extends SettingBase { state.instantApp = instantApp; state.virtualPreload = virtualPreload; state.harmfulAppWarning = harmfulAppWarning; + state.splashScreenTheme = splashScreenTheme; onChanged(); } @@ -522,7 +524,8 @@ public abstract class PackageSettingBase extends SettingBase { otherState.instantApp, otherState.virtualPreload, otherState.lastDisableAppCaller, otherState.enabledComponents, otherState.disabledComponents, - otherState.installReason, otherState.uninstallReason, otherState.harmfulAppWarning); + otherState.installReason, otherState.uninstallReason, otherState.harmfulAppWarning, + otherState.splashScreenTheme); } ArraySet<String> getEnabledComponents(int userId) { @@ -723,6 +726,26 @@ public abstract class PackageSettingBase extends SettingBase { } /** + * @param userId the specified user to modify the theme for + * @param themeName the theme name to persist + * @see android.window.SplashScreen#setSplashScreenTheme(int) + */ + public void setSplashScreenTheme(@UserIdInt int userId, @Nullable String themeName) { + modifyUserState(userId).splashScreenTheme = themeName; + } + + /** + * @param userId the specified user to get the theme setting from + * @return the theme name previously persisted for the user or null + * if no splashscreen theme is persisted. + * @see android.window.SplashScreen#setSplashScreenTheme(int) + */ + @Nullable + public String getSplashScreenTheme(@UserIdInt int userId) { + return readUserState(userId).splashScreenTheme; + } + + /** * @return True if package is still being loaded, false if the package is fully loaded. */ public boolean isPackageLoading() { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index e409019e0da6..b6d4a5b88f8a 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -340,6 +340,7 @@ public final class Settings implements Watchable, Snappable { private static final String ATTR_INSTANT_APP = "instant-app"; private static final String ATTR_VIRTUAL_PRELOAD = "virtual-preload"; private static final String ATTR_HARMFUL_APP_WARNING = "harmful-app-warning"; + private static final String ATTR_SPLASH_SCREEN_THEME = "splash-screen-theme"; private static final String ATTR_PACKAGE_NAME = "packageName"; private static final String ATTR_FINGERPRINT = "fingerprint"; @@ -939,7 +940,9 @@ public final class Settings implements Watchable, Snappable { null /*disabledComponents*/, PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.UNINSTALL_REASON_UNKNOWN, - null /*harmfulAppWarning*/); + null, /*harmfulAppWarning*/ + null /*splashscreenTheme*/ + ); } } } @@ -1578,7 +1581,8 @@ public final class Settings implements Watchable, Snappable { null /*disabledComponents*/, PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.UNINSTALL_REASON_UNKNOWN, - null /*harmfulAppWarning*/); + null /*harmfulAppWarning*/, + null /* splashScreenTheme*/); } return; } @@ -1666,6 +1670,8 @@ public final class Settings implements Watchable, Snappable { PackageManager.INSTALL_REASON_UNKNOWN); final int uninstallReason = parser.getAttributeInt(null, ATTR_UNINSTALL_REASON, PackageManager.UNINSTALL_REASON_UNKNOWN); + final String splashScreenTheme = parser.getAttributeValue(null, + ATTR_SPLASH_SCREEN_THEME); ArraySet<String> enabledComponents = null; ArraySet<String> disabledComponents = null; @@ -1738,7 +1744,8 @@ public final class Settings implements Watchable, Snappable { ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched, hidden, distractionFlags, suspended, suspendParamsMap, instantApp, virtualPreload, enabledCaller, enabledComponents, - disabledComponents, installReason, uninstallReason, harmfulAppWarning); + disabledComponents, installReason, uninstallReason, harmfulAppWarning, + splashScreenTheme); mDomainVerificationManager.setLegacyUserState(name, userId, verifState); } else if (tagName.equals("preferred-activities")) { @@ -1995,6 +2002,10 @@ public final class Settings implements Watchable, Snappable { serializer.attribute(null, ATTR_HARMFUL_APP_WARNING, ustate.harmfulAppWarning); } + if (ustate.splashScreenTheme != null) { + serializer.attribute(null, ATTR_SPLASH_SCREEN_THEME, + ustate.splashScreenTheme); + } if (ustate.suspended) { for (int i = 0; i < ustate.suspendParams.size(); i++) { final String suspendingPackage = ustate.suspendParams.keyAt(i); diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 007393ab80fb..7f18c4b4486a 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -168,7 +168,7 @@ public class ShortcutService extends IShortcutService.Stub { static final boolean DEBUG = false; // STOPSHIP if true static final boolean DEBUG_LOAD = false; // STOPSHIP if true static final boolean DEBUG_PROCSTATE = false; // STOPSHIP if true - static final boolean DEBUG_REBOOT = true; + static final boolean DEBUG_REBOOT = false; // STOPSHIP if true @VisibleForTesting static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day @@ -1992,10 +1992,11 @@ public class ShortcutService extends IShortcutService.Stub { packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts); verifyStates(); + + ret.complete(true); } catch (Exception e) { ret.completeExceptionally(e); } - ret.complete(true); }); return ret; } @@ -2240,6 +2241,8 @@ public class ShortcutService extends IShortcutService.Stub { packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts); + reportShortcutUsedInternal(packageName, shortcut.getId(), userId); + verifyStates(); ret.complete(null); @@ -2850,12 +2853,7 @@ public class ShortcutService extends IShortcutService.Stub { } } - final long token = injectClearCallingIdentity(); - try { - mUsageStatsManagerInternal.reportShortcutUsage(packageName, shortcutId, userId); - } finally { - injectRestoreCallingIdentity(token); - } + reportShortcutUsedInternal(packageName, shortcutId, userId); ret.complete(true); } catch (Exception e) { ret.completeExceptionally(e); @@ -2864,6 +2862,15 @@ public class ShortcutService extends IShortcutService.Stub { return ret; } + private void reportShortcutUsedInternal(String packageName, String shortcutId, int userId) { + final long token = injectClearCallingIdentity(); + try { + mUsageStatsManagerInternal.reportShortcutUsage(packageName, shortcutId, userId); + } finally { + injectRestoreCallingIdentity(token); + } + } + @Override public boolean isRequestPinItemSupported(int callingUserId, int requestType) { final long token = injectClearCallingIdentity(); 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 1e92ca60ce2f..50f958f558f7 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -211,6 +211,7 @@ final class DefaultPermissionGrantPolicy { NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_ADVERTISE); NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_CONNECT); NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_SCAN); + NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.UWB_RANGING); } private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1; diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java index 622b758e0e21..3a097a71e3e9 100644 --- a/services/core/java/com/android/server/policy/AppOpsPolicy.java +++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java @@ -280,14 +280,15 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat private static void updateAllowListedTagsForPackageLocked(int uid, String packageName, Set<String> allowListedTags, ConcurrentHashMap<Integer, ArrayMap<String, ArraySet<String>>> datastore) { + final int appId = UserHandle.getAppId(uid); // 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 = datastore.get(uid); - if (uidTags != null) { - uidTags = new ArrayMap<>(uidTags); + ArrayMap<String, ArraySet<String>> appIdTags = datastore.get(appId); + if (appIdTags != null) { + appIdTags = new ArrayMap<>(appIdTags); } - ArraySet<String> packageTags = (uidTags != null) ? uidTags.get(packageName) : null; + ArraySet<String> packageTags = (appIdTags != null) ? appIdTags.get(packageName) : null; if (packageTags != null) { packageTags = new ArraySet<>(packageTags); } @@ -299,17 +300,17 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat } else { packageTags = new ArraySet<>(allowListedTags); } - if (uidTags == null) { - uidTags = new ArrayMap<>(); + if (appIdTags == null) { + appIdTags = new ArrayMap<>(); } - uidTags.put(packageName, packageTags); - datastore.put(uid, uidTags); - } else if (uidTags != null) { - uidTags.remove(packageName); - if (!uidTags.isEmpty()) { - datastore.put(uid, uidTags); + appIdTags.put(packageName, packageTags); + datastore.put(appId, appIdTags); + } else if (appIdTags != null) { + appIdTags.remove(packageName); + if (!appIdTags.isEmpty()) { + datastore.put(appId, appIdTags); } else { - datastore.remove(uid); + datastore.remove(appId); } } } @@ -318,9 +319,10 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat @NonNull String attributionTag, @NonNull Map<Integer, ArrayMap<String, ArraySet<String>>> mappedOps) { // Only a single lookup from the underlying concurrent data structure - final ArrayMap<String, ArraySet<String>> uidTags = mappedOps.get(uid); - if (uidTags != null) { - final ArraySet<String> packageTags = uidTags.get(packageName); + final int appId = UserHandle.getAppId(uid); + final ArrayMap<String, ArraySet<String>> appIdTags = mappedOps.get(appId); + if (appIdTags != null) { + final ArraySet<String> packageTags = appIdTags.get(packageName); if (packageTags != null && packageTags.contains(attributionTag)) { return true; } diff --git a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java index 6f6bdac61fad..edd5f5f415c6 100644 --- a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java +++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java @@ -83,6 +83,7 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider, private static final String TAG = "DeviceStateProviderImpl"; private static final BooleanSupplier TRUE_BOOLEAN_SUPPLIER = () -> true; + private static final BooleanSupplier FALSE_BOOLEAN_SUPPLIER = () -> false; @VisibleForTesting static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(MINIMUM_DEVICE_STATE, @@ -152,7 +153,7 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider, private final DeviceState[] mOrderedStates; // Map of state identifier to a boolean supplier that returns true when all required conditions // are met for the device to be in the state. - private final SparseArray<BooleanSupplier> mStateConditions; + private final SparseArray<BooleanSupplier> mStateConditions = new SparseArray<>(); @Nullable @GuardedBy("mLock") @@ -177,6 +178,11 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider, Arrays.sort(orderedStates, Comparator.comparingInt(DeviceState::getIdentifier)); mOrderedStates = orderedStates; + setStateConditions(deviceStates, stateConditions); + } + + private void setStateConditions(@NonNull List<DeviceState> deviceStates, + @NonNull List<Conditions> stateConditions) { // Whether or not this instance should register to receive lid switch notifications from // InputManagerInternal. If there are no device state conditions that are based on the lid // switch there is no need to register for a callback. @@ -185,7 +191,6 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider, // The set of Sensor(s) that this instance should register to receive SensorEvent(s) from. final ArraySet<Sensor> sensorsToListenTo = new ArraySet<>(); - mStateConditions = new SparseArray<>(); for (int i = 0; i < stateConditions.size(); i++) { final int state = deviceStates.get(i).getIdentifier(); final Conditions conditions = stateConditions.get(i); @@ -194,12 +199,20 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider, continue; } + // Whether or not all the required hardware components could be found that match the + // requirements from the config. + boolean allRequiredComponentsFound = true; + // Whether or not this condition requires the lid switch. + boolean lidSwitchRequired = false; + // Set of sensors required for this condition. + ArraySet<Sensor> sensorsRequired = new ArraySet<>(); + List<BooleanSupplier> suppliers = new ArrayList<>(); LidSwitchCondition lidSwitchCondition = conditions.getLidSwitch(); if (lidSwitchCondition != null) { suppliers.add(new LidSwitchBooleanSupplier(lidSwitchCondition.getOpen())); - shouldListenToLidSwitch = true; + lidSwitchRequired = true; } List<SensorCondition> sensorConditions = conditions.getSensor(); @@ -210,22 +223,33 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider, final Sensor foundSensor = findSensor(expectedSensorType, expectedSensorName); if (foundSensor == null) { - throw new IllegalStateException("Failed to find Sensor with type: " - + expectedSensorType + " and name: " + expectedSensorName); + Slog.e(TAG, "Failed to find Sensor with type: " + expectedSensorType + + " and name: " + expectedSensorName); + allRequiredComponentsFound = false; + break; } suppliers.add(new SensorBooleanSupplier(foundSensor, sensorCondition.getValue())); - sensorsToListenTo.add(foundSensor); + sensorsRequired.add(foundSensor); } - if (suppliers.size() > 1) { - mStateConditions.put(state, new AndBooleanSupplier(suppliers)); - } else if (suppliers.size() > 0) { - // No need to wrap with an AND supplier if there is only 1. - mStateConditions.put(state, suppliers.get(0)); + if (allRequiredComponentsFound) { + shouldListenToLidSwitch |= lidSwitchRequired; + sensorsToListenTo.addAll(sensorsRequired); + + if (suppliers.size() > 1) { + mStateConditions.put(state, new AndBooleanSupplier(suppliers)); + } else if (suppliers.size() > 0) { + // No need to wrap with an AND supplier if there is only 1. + mStateConditions.put(state, suppliers.get(0)); + } else { + // There are no conditions for this state. Default to always true. + mStateConditions.put(state, TRUE_BOOLEAN_SUPPLIER); + } } else { - // There are no conditions for this state. Default to always true. - mStateConditions.put(state, TRUE_BOOLEAN_SUPPLIER); + // Failed to setup this condition. This can happen if a sensor is missing. Default + // this state to always false. + mStateConditions.put(state, FALSE_BOOLEAN_SUPPLIER); } } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 805252260209..c4aca6c18453 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -102,6 +102,7 @@ import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.os.BackgroundThread; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; @@ -2926,16 +2927,13 @@ public final class PowerManagerService extends SystemService private void scheduleSandmanLocked() { if (!mSandmanScheduled) { mSandmanScheduled = true; - Message msg = mHandler.obtainMessage(MSG_SANDMAN); - msg.setAsynchronous(true); - mHandler.sendMessage(msg); - } - } - - private void handleSandman() { - for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) { - if (mDisplayGroupPowerStateMapper.isSandmanSupported(id)) { - handleSandman(id); + for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) { + if (mDisplayGroupPowerStateMapper.isSandmanSupported(id)) { + Message msg = mHandler.obtainMessage(MSG_SANDMAN); + msg.arg1 = id; + msg.setAsynchronous(true); + mHandler.sendMessage(msg); + } } } } @@ -2953,6 +2951,11 @@ public final class PowerManagerService extends SystemService final int wakefulness; synchronized (mLock) { mSandmanScheduled = false; + final int[] ids = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked(); + if (!ArrayUtils.contains(ids, groupId)) { + // Group has been removed. + return; + } // TODO (b/175764708): Support per-display doze. wakefulness = getWakefulnessLocked(); if ((wakefulness == WAKEFULNESS_DREAMING || wakefulness == WAKEFULNESS_DOZING) && @@ -2986,6 +2989,12 @@ public final class PowerManagerService extends SystemService // Update dream state. synchronized (mLock) { + final int[] ids = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked(); + if (!ArrayUtils.contains(ids, groupId)) { + // Group has been removed. + return; + } + // Remember the initial battery level when the dream started. if (startDreaming && isDreaming) { mBatteryLevelWhenDreamStarted = mBatteryLevel; @@ -4770,7 +4779,7 @@ public final class PowerManagerService extends SystemService handleUserActivityTimeout(); break; case MSG_SANDMAN: - handleSandman(); + handleSandman(msg.arg1); break; case MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT: handleScreenBrightnessBoostTimeout(); diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java index d5ab574b5617..6f0741d20e45 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.RECORD_AUDIO; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.AppOpsManager; import android.content.Context; import android.content.PermissionChecker; import android.media.permission.Identity; @@ -132,7 +133,12 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware * Throws a {@link SecurityException} iff the originator has permission to receive data. */ void enforcePermissionsForDataDelivery(@NonNull Identity identity, @NonNull String reason) { - enforcePermissionForDataDelivery(mContext, identity, RECORD_AUDIO, reason); + // START TEMP HACK + enforcePermissionForPreflight(mContext, identity, RECORD_AUDIO); + int hotwordOp = AppOpsManager.strOpToOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD); + mContext.getSystemService(AppOpsManager.class).noteOpNoThrow(hotwordOp, identity.uid, + identity.packageName, identity.attributionTag, reason); + // END TEMP HACK enforcePermissionForDataDelivery(mContext, identity, CAPTURE_AUDIO_HOTWORD, reason); } diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java index 52236a81c607..8b2b8b1cfbac 100644 --- a/services/core/java/com/android/server/testharness/TestHarnessModeService.java +++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java @@ -284,6 +284,9 @@ public class TestHarnessModeService extends SystemService { private class TestHarnessModeShellCommand extends ShellCommand { @Override public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } switch (cmd) { case "enable": case "restore": diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index f014b0749396..4b71742c86c8 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -41,6 +41,7 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.database.ContentObserver; import android.graphics.drawable.Drawable; +import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; import android.net.Uri; import android.os.Binder; @@ -188,8 +189,6 @@ public class TrustManagerService extends SystemService { private boolean mTrustAgentsCanRun = false; private int mCurrentUser = UserHandle.USER_SYSTEM; - private Authorization mAuthorizationService; - public TrustManagerService(Context context) { super(context); mContext = context; @@ -199,7 +198,6 @@ public class TrustManagerService extends SystemService { mStrongAuthTracker = new StrongAuthTracker(context); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); mSettingsObserver = new SettingsObserver(mHandler); - mAuthorizationService = new Authorization(); } @Override @@ -701,13 +699,14 @@ public class TrustManagerService extends SystemService { } if (changed) { dispatchDeviceLocked(userId, locked); - - Authorization.onLockScreenEvent(locked, userId, null); + Authorization.onLockScreenEvent(locked, userId, null, + getBiometricSids(userId)); // Also update the user's profiles who have unified challenge, since they // share the same unlocked state (see {@link #isDeviceLocked(int)}) for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) { if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) { - mAuthorizationService.onLockScreenEvent(locked, profileHandle, null); + Authorization.onLockScreenEvent(locked, profileHandle, null, + getBiometricSids(profileHandle)); } } } @@ -1047,6 +1046,14 @@ public class TrustManagerService extends SystemService { } } + private long[] getBiometricSids(int userId) { + BiometricManager biometricManager = mContext.getSystemService(BiometricManager.class); + if (biometricManager == null) { + return null; + } + return biometricManager.getAuthenticatorIds(userId); + } + // User lifecycle @Override @@ -1258,7 +1265,8 @@ public class TrustManagerService extends SystemService { mDeviceLockedForUser.put(userId, locked); } - Authorization.onLockScreenEvent(locked, userId, null); + Authorization.onLockScreenEvent(locked, userId, null, + getBiometricSids(userId)); if (locked) { try { diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 6ca3c4b66024..65b947c1fcdd 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -52,7 +52,6 @@ import android.net.NetworkProvider; import android.net.NetworkScore; import android.net.RouteInfo; import android.net.TelephonyNetworkSpecifier; -import android.net.TunnelConnectionParams; import android.net.Uri; import android.net.annotations.PolicyDirection; import android.net.ipsec.ike.ChildSessionCallback; @@ -1559,8 +1558,22 @@ public class VcnGatewayConnection extends StateMachine { teardownAsynchronously(); } /* networkUnwantedCallback */, (status) -> { - if (status == NetworkAgent.VALIDATION_STATUS_VALID) { - clearFailedAttemptCounterAndSafeModeAlarm(); + switch (status) { + case NetworkAgent.VALIDATION_STATUS_VALID: + clearFailedAttemptCounterAndSafeModeAlarm(); + break; + case NetworkAgent.VALIDATION_STATUS_NOT_VALID: + // Will only set a new alarm if no safe mode alarm is + // currently scheduled. + setSafeModeAlarm(); + break; + default: + Slog.wtf( + TAG, + "Unknown validation status " + + status + + "; ignoring"); + break; } } /* validationStatusCallback */); @@ -1838,7 +1851,7 @@ public class VcnGatewayConnection extends StateMachine { private long getNextRetryIntervalsMs() { final int retryDelayIndex = mFailedAttempts - 1; - final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMs(); + final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMillis(); // Repeatedly use last item in retry timeout list. if (retryDelayIndex >= retryIntervalsMs.length) { @@ -1924,14 +1937,8 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, @Nullable UnderlyingNetworkRecord underlying) { - final TunnelConnectionParams tunnelParams = + final IkeTunnelConnectionParams ikeTunnelParams = gatewayConnectionConfig.getTunnelConnectionParams(); - if (!(tunnelParams instanceof IkeTunnelConnectionParams)) { - throw new IllegalStateException( - "TunnelConnectionParams is not IkeTunnelConnectionParams"); - } - - final IkeTunnelConnectionParams ikeTunnelParams = (IkeTunnelConnectionParams) tunnelParams; final LinkProperties lp = new LinkProperties(); lp.setInterfaceName(tunnelIface.getInterfaceName()); @@ -2138,32 +2145,16 @@ public class VcnGatewayConnection extends StateMachine { } private IkeSessionParams buildIkeParams(@NonNull Network network) { - final TunnelConnectionParams tunnelConnectionParams = + final IkeTunnelConnectionParams ikeTunnelConnectionParams = mConnectionConfig.getTunnelConnectionParams(); - - if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) { - final IkeTunnelConnectionParams ikeTunnelConnectionParams = - (IkeTunnelConnectionParams) tunnelConnectionParams; - final IkeSessionParams.Builder builder = - new IkeSessionParams.Builder(ikeTunnelConnectionParams.getIkeSessionParams()); - builder.setNetwork(network); - - return builder.build(); - } - - throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams"); + final IkeSessionParams.Builder builder = + new IkeSessionParams.Builder(ikeTunnelConnectionParams.getIkeSessionParams()); + builder.setNetwork(network); + return builder.build(); } private ChildSessionParams buildChildParams() { - final TunnelConnectionParams tunnelConnectionParams = - mConnectionConfig.getTunnelConnectionParams(); - - if (tunnelConnectionParams instanceof IkeTunnelConnectionParams) { - return ((IkeTunnelConnectionParams) tunnelConnectionParams) - .getTunnelModeChildSessionParams(); - } - - throw new IllegalStateException("TunnelConnectionParams is not IkeTunnelConnectionParams"); + return mConnectionConfig.getTunnelConnectionParams().getTunnelModeChildSessionParams(); } @VisibleForTesting(visibility = Visibility.PRIVATE) diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index efee0a1133b6..eb9ab3668dac 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -827,9 +827,9 @@ class ActivityClientController extends IActivityClientController.Stub { if (rootTask.inFreeformWindowingMode()) { rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - } else if (!mService.mSupportsNonResizableMultiWindow && r.inSizeCompatMode()) { - throw new IllegalStateException("Size-compat windows are currently not" - + "freeform-enabled"); + } else if (!r.supportsFreeform()) { + throw new IllegalStateException( + "This activity is currently not freeform-enabled"); } else if (rootTask.getParent().inFreeformWindowingMode()) { // If the window is on a freeform display, set it to undefined. It will be // resolved to freeform and it can adjust windowing mode when the display mode diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index ef54e8e6d750..6957aa0154e1 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2465,8 +2465,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (windowingMode == WINDOWING_MODE_PINNED && info.supportsPictureInPicture()) { return false; } - if (WindowConfiguration.inMultiWindowMode(windowingMode) - && mAtmService.mSupportsNonResizableMultiWindow + if (WindowConfiguration.inMultiWindowMode(windowingMode) && supportsMultiWindow() && !mAtmService.mForceResizableActivities) { // The non resizable app will be letterboxed instead of being forced resizable. return false; @@ -3523,7 +3522,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } // Reset the last saved PiP snap fraction on removal. - mDisplayContent.mPinnedTaskControllerLocked.onActivityHidden(mActivityComponent); + mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent); mWmService.mEmbeddedWindowController.onActivityRemoved(this); mRemovingFromDisplay = false; } @@ -4882,7 +4881,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this); mAppStopped = true; // Reset the last saved PiP snap fraction on app stop. - mDisplayContent.mPinnedTaskControllerLocked.onActivityHidden(mActivityComponent); + mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent); destroySurfaces(); // Remove any starting window that was added for this app if they are still around. removeStartingWindow(); @@ -6604,6 +6603,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } + mDisplayContent.mPinnedTaskController.onCancelFixedRotationTransform(task); // Perform rotation animation according to the rotation of this activity. startFreezingScreen(originalDisplayRotation); // This activity may relaunch or perform configuration change so once it has reported drawn, @@ -6995,6 +6995,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // fixed-orientation requests. return; } + if (newParentConfig.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED) { + // PiP bounds have higher priority than the requested orientation. Otherwise the + // activity may be squeezed into a small piece. + return; + } final Rect resolvedBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds(); @@ -7386,8 +7391,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + final boolean wasInPictureInPicture = inPinnedWindowingMode(); final DisplayContent display = mDisplayContent; - if (inPinnedWindowingMode() && attachedToProcess() && display != null) { + if (wasInPictureInPicture && attachedToProcess() && display != null) { // If the PIP activity is changing to fullscreen with display orientation change, the // fixed rotation will take effect that requires to send fixed rotation adjustments // before the process configuration (if the process is a configuration listener of the @@ -7419,6 +7425,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A onMergedOverrideConfigurationChanged(); } + // Before PiP animation is done, th windowing mode of the activity is still the previous + // mode (see RootWindowContainer#moveActivityToPinnedRootTask). So once the windowing mode + // of activity is changed, it is the signal of the last step to update the PiP states. + if (!wasInPictureInPicture && inPinnedWindowingMode() && task != null) { + mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, task.getBounds()); + } + if (display == null) { return; } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 9be973be87fc..08a9f0928b8b 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2761,8 +2761,8 @@ class ActivityStarter { final boolean onTop = (aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind; - return mRootWindowContainer.getLaunchRootTask(r, aOptions, task, onTop, mLaunchParams, - mRequest.realCallingPid, mRequest.realCallingUid); + return mRootWindowContainer.getLaunchRootTask(r, aOptions, task, mSourceRootTask, onTop, + mLaunchParams, launchFlags, mRequest.realCallingPid, mRequest.realCallingUid); } private boolean isLaunchModeOneOf(int mode1, int mode2) { diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index aa993bfeaf2e..9178a8d16d16 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -561,6 +561,14 @@ public abstract class ActivityTaskManagerInternal { public abstract ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry(); /** + * Returns the URI permission owner associated with the given activity (see + * {@link ActivityRecord#getUriPermissionsLocked()}). If the passed-in activity token is + * invalid, returns null. + */ + @Nullable + public abstract IBinder getUriPermissionOwnerForActivity(@NonNull IBinder activityToken); + + /** * Gets bitmap snapshot of the provided task id. * * <p>Warning! this may restore the snapshot from disk so can block, don't call in a latency diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 0570f6cdfa77..61985730c49f 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -3340,11 +3340,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override - public boolean supportsNonResizableMultiWindow() { - return mSupportsNonResizableMultiWindow; - } - - @Override public boolean updateConfiguration(Configuration values) { mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()"); @@ -6256,6 +6251,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } + @Nullable + @Override + public IBinder getUriPermissionOwnerForActivity(@NonNull IBinder activityToken) { + ActivityTaskManagerService.enforceNotIsolatedCaller("getUriPermissionOwnerForActivity"); + synchronized (mGlobalLock) { + ActivityRecord r = ActivityRecord.isInRootTaskLocked(activityToken); + return (r == null) ? null : r.getUriPermissionsLocked().getExternalToken(); + } + } + @Override public TaskSnapshot getTaskSnapshotBlocking( int taskId, boolean isLowResolution) { diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 9d225e1ab1f6..df1fec9ad0da 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -2254,7 +2254,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { scheduleUpdatePictureInPictureModeIfNeeded(task, rootTask.getRequestedOverrideBounds()); } - private void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetRootTaskBounds) { + void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetRootTaskBounds) { final PooledConsumer c = PooledLambda.obtainConsumer( ActivityTaskSupervisor::addToPipModeChangedList, this, PooledLambda.__(ActivityRecord.class)); @@ -2278,16 +2278,6 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { mMultiWindowModeChangedActivities.remove(r); } - void updatePictureInPictureMode(Task task, Rect targetRootTaskBounds, boolean forceUpdate) { - mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG); - final PooledConsumer c = PooledLambda.obtainConsumer( - ActivityRecord::updatePictureInPictureMode, - PooledLambda.__(ActivityRecord.class), targetRootTaskBounds, forceUpdate); - task.getRootTask().setBounds(targetRootTaskBounds); - task.forAllActivities(c); - c.recycle(); - } - void wakeUp(String reason) { mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_APPLICATION, "android.server.am:TURN_ON:" + reason); diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 43326df1a143..d5a76199f7b8 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -1691,7 +1691,11 @@ public class AppTransition implements Dump { static boolean isTaskTransitOld(@TransitionOldType int transit) { return isTaskOpenTransitOld(transit) - || transit == TRANSIT_OLD_TASK_CLOSE + || isTaskCloseTransitOld(transit); + } + + static boolean isTaskCloseTransitOld(@TransitionOldType int transit) { + return transit == TRANSIT_OLD_TASK_CLOSE || transit == TRANSIT_OLD_TASK_TO_BACK; } diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java index d920267bb44d..ff1016855287 100644 --- a/services/core/java/com/android/server/wm/BlurController.java +++ b/services/core/java/com/android/server/wm/BlurController.java @@ -22,37 +22,32 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.database.ContentObserver; import android.net.ConnectivityManager; import android.os.PowerManager; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.provider.Settings; import android.view.ICrossWindowBlurEnabledListener; -import com.android.internal.annotations.GuardedBy; - /** * Keeps track of the different factors that determine whether cross-window blur is enabled * or disabled. Also keeps a list of all interested listeners and notifies them when the * blur enabled state changes. */ final class BlurController { - private final PowerManager mPowerManager; + private final Context mContext; private final RemoteCallbackList<ICrossWindowBlurEnabledListener> mBlurEnabledListeners = new RemoteCallbackList<>(); // We don't use the WM global lock, because the BlurController is not involved in window // drawing and only receives binder calls that don't need synchronization with the rest of WM private final Object mLock = new Object(); - @GuardedBy("mLock") - boolean mBlurEnabled; - @GuardedBy("mLock") - boolean mBlurForceDisabled; - @GuardedBy("mLock") - boolean mInBatterySaverMode; + private volatile boolean mBlurEnabled; + private boolean mInPowerSaveMode; + private boolean mBlurDisabledSetting; BlurController(Context context, PowerManager powerManager) { - mPowerManager = powerManager; - mInBatterySaverMode = mPowerManager.isPowerSaveMode(); - updateBlurEnabledLocked(); + mContext = context; IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); @@ -60,18 +55,36 @@ final class BlurController { @Override public void onReceive(Context context, Intent intent) { if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) { - setBatterySaverEnabled(mPowerManager.isPowerSaveMode()); + // onReceive always gets called on the same thread, so there is no + // multi-threaded execution here. Thus, we don't have to hold mLock here. + mInPowerSaveMode = powerManager.isPowerSaveMode(); + updateBlurEnabled(); } } }, filter, null, null); + mInPowerSaveMode = powerManager.isPowerSaveMode(); + + context.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.DISABLE_WINDOW_BLURS), false, + new ContentObserver(null) { + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + // onChange always gets called on the same thread, so there is no + // multi-threaded execution here. Thus, we don't have to hold mLock here. + mBlurDisabledSetting = getBlurDisabledSetting(); + updateBlurEnabled(); + } + }); + mBlurDisabledSetting = getBlurDisabledSetting(); + + updateBlurEnabled(); } boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) { if (listener == null) return false; mBlurEnabledListeners.register(listener); - synchronized (mLock) { - return mBlurEnabled; - } + return getBlurEnabled(); } void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) { @@ -79,29 +92,20 @@ final class BlurController { mBlurEnabledListeners.unregister(listener); } - void setForceCrossWindowBlurDisabled(boolean disable) { - synchronized (mLock) { - mBlurForceDisabled = disable; - updateBlurEnabledLocked(); - } - + boolean getBlurEnabled() { + return mBlurEnabled; } - void setBatterySaverEnabled(boolean enabled) { + private void updateBlurEnabled() { synchronized (mLock) { - mInBatterySaverMode = enabled; - updateBlurEnabledLocked(); - } - } - - private void updateBlurEnabledLocked() { - final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurForceDisabled - && !mInBatterySaverMode; - if (mBlurEnabled == newEnabled) { - return; + final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurDisabledSetting + && !mInPowerSaveMode; + if (mBlurEnabled == newEnabled) { + return; + } + mBlurEnabled = newEnabled; + notifyBlurEnabledChangedLocked(newEnabled); } - mBlurEnabled = newEnabled; - notifyBlurEnabledChangedLocked(newEnabled); } private void notifyBlurEnabledChangedLocked(boolean enabled) { @@ -117,4 +121,9 @@ final class BlurController { } mBlurEnabledListeners.finishBroadcast(); } + + private boolean getBlurDisabledSetting() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DISABLE_WINDOW_BLURS, 0) == 1; + } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index f017c0afd630..a10847876ab6 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -466,7 +466,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private boolean mDeferredRemoval; final DockedTaskDividerController mDividerControllerLocked; - final PinnedTaskController mPinnedTaskControllerLocked; + final PinnedTaskController mPinnedTaskController; final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>(); /** A collection of windows that provide tap exclude regions inside of them. */ @@ -1019,7 +1019,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } mWindowCornerRadius = mDisplayPolicy.getWindowCornerRadius(); mDividerControllerLocked = new DockedTaskDividerController(this); - mPinnedTaskControllerLocked = new PinnedTaskController(mWmService, this); + mPinnedTaskController = new PinnedTaskController(mWmService, this); final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession) .setOpaque(true) @@ -1538,6 +1538,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // to cover the activity configuration change. return false; } + if (r.mStartingData != null && r.mStartingData.hasImeSurface()) { + // Currently it is unknown that when will IME window be ready. Reject the case to + // avoid flickering by showing IME in inconsistent orientation. + return false; + } if (checkOpening) { if (!mAppTransition.isTransitionSet() || !mOpeningApps.contains(r)) { // Apply normal rotation animation in case of the activity set different requested @@ -1575,15 +1580,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } return false; } - if (!r.getParent().matchParentBounds()) { + if (!r.getDisplayArea().matchParentBounds()) { // Because the fixed rotated configuration applies to activity directly, if its parent // has it own policy for bounds, the activity bounds based on parent is unknown. return false; } - if (mPinnedTaskControllerLocked.isPipActiveOrWindowingModeChanging()) { - // Use normal rotation animation because seamless PiP rotation is not supported yet. - return false; - } setFixedRotationLaunchingApp(r, rotation); return true; @@ -1669,6 +1670,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (mFixedRotationLaunchingApp == null) { return; } + if (mPinnedTaskController.shouldDeferOrientationChange()) { + // Wait for the PiP animation to finish. + return; + } // Update directly because the app which will change the orientation of display is ready. if (mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */)) { sendNewConfiguration(); @@ -1839,6 +1844,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp forAllWindows(w -> { w.seamlesslyRotateIfAllowed(transaction, oldRotation, rotation, rotateSeamlessly); }, true /* traverseTopToBottom */); + mPinnedTaskController.startSeamlessRotationIfNeeded(transaction); } mWmService.mDisplayManagerInternal.performTraversal(transaction); @@ -2107,9 +2113,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } // Check if input device can dispatch events to current display. - // If display type is virtual, will follow the default display. - if (!mWmService.mInputManager.canDispatchToDisplay(device.getId(), - displayInfo.type == Display.TYPE_VIRTUAL ? DEFAULT_DISPLAY : mDisplayId)) { + if (!mWmService.mInputManager.canDispatchToDisplay(device.getId(), mDisplayId)) { continue; } @@ -2335,7 +2339,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } PinnedTaskController getPinnedTaskController() { - return mPinnedTaskControllerLocked; + return mPinnedTaskController; } /** @@ -2394,12 +2398,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @Override public void onConfigurationChanged(Configuration newParentConfig) { - // update resources before cascade so that root docked/pinned tasks use the correct info - preOnConfigurationChanged(); final int lastOrientation = getConfiguration().orientation; super.onConfigurationChanged(newParentConfig); if (mDisplayPolicy != null) { mDisplayPolicy.onConfigurationChanged(); + mPinnedTaskController.onPostDisplayConfigurationChanged(); } if (lastOrientation != getConfiguration().orientation) { @@ -2410,19 +2413,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } - /** - * Updates the resources used by docked/pinned controllers. This needs to be called at the - * beginning of a configuration update cascade since the metrics from these resources are used - * for bounds calculations. - */ - void preOnConfigurationChanged() { - final PinnedTaskController pinnedTaskController = getPinnedTaskController(); - - if (pinnedTaskController != null) { - getPinnedTaskController().onConfigurationChanged(); - } - } - @Override boolean fillsParent() { return true; @@ -2964,7 +2954,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp final boolean imeVisible = imeWin != null && imeWin.isVisible() && imeWin.isDisplayed(); final int imeHeight = getInputMethodWindowVisibleHeight(); - mPinnedTaskControllerLocked.setAdjustedForIme(imeVisible, imeHeight); + mPinnedTaskController.setAdjustedForIme(imeVisible, imeHeight); } int getInputMethodWindowVisibleHeight() { @@ -3192,7 +3182,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } pw.println(); - mPinnedTaskControllerLocked.dump(prefix, pw); + mPinnedTaskController.dump(prefix, pw); pw.println(); mDisplayFrames.dump(prefix, pw); diff --git a/services/core/java/com/android/server/wm/DisplayHashController.java b/services/core/java/com/android/server/wm/DisplayHashController.java index af0c3e3f319e..94d81fbb7cc9 100644 --- a/services/core/java/com/android/server/wm/DisplayHashController.java +++ b/services/core/java/com/android/server/wm/DisplayHashController.java @@ -129,10 +129,10 @@ public class DisplayHashController { private boolean mParsedXml; /** - * Specified throttle time in milliseconds. Don't allow an app to generate a display hash more - * than once per throttleTime + * Specified duration between requests to generate a display hash in milliseconds. Requests + * faster than this delay will be throttled. */ - private int mThrottleDurationMillis = 0; + private int mDurationBetweenRequestMillis = 0; /** * The last time an app requested to generate a display hash in System time. @@ -203,8 +203,8 @@ public class DisplayHashController { return true; } - int throttleDurationMs = getThrottleDurationMillis(); - if (currentTime - mLastRequestTimeMs < throttleDurationMs) { + int mDurationBetweenRequestsMs = getDurationBetweenRequestMillis(); + if (currentTime - mLastRequestTimeMs < mDurationBetweenRequestsMs) { return false; } @@ -233,7 +233,7 @@ public class DisplayHashController { (float) size.getHeight() / boundsInWindow.height()); } - args.setGrayscale(displayHashParams.isUseGrayscale()); + args.setGrayscale(displayHashParams.isGrayscaleBuffer()); SurfaceControl.ScreenshotHardwareBuffer screenshotHardwareBuffer = SurfaceControl.captureLayers(args.build()); @@ -356,11 +356,11 @@ public class DisplayHashController { } } - private int getThrottleDurationMillis() { + private int getDurationBetweenRequestMillis() { if (!parseXmlProperties()) { return 0; } - return mThrottleDurationMillis; + return mDurationBetweenRequestMillis; } private boolean parseXmlProperties() { @@ -406,8 +406,8 @@ public class DisplayHashController { } TypedArray sa = res.obtainAttributes(attrs, R.styleable.DisplayHashingService); - mThrottleDurationMillis = sa.getInt( - R.styleable.DisplayHashingService_throttleDurationMillis, 0); + mDurationBetweenRequestMillis = sa.getInt( + R.styleable.DisplayHashingService_durationBetweenRequestsMillis, 0); sa.recycle(); mParsedXml = true; return true; diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index e1fc75e6fd9f..0e73d7956748 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -254,7 +254,7 @@ public class DisplayRotation { if (isDefaultDisplay) { final Handler uiHandler = UiThread.getHandler(); - mOrientationListener = new OrientationListener(mContext, uiHandler, mService); + mOrientationListener = new OrientationListener(mContext, uiHandler); mOrientationListener.setCurrentRotation(mRotation); mSettingsObserver = new SettingsObserver(uiHandler); mSettingsObserver.observe(); @@ -1514,8 +1514,8 @@ public class DisplayRotation { final SparseArray<Runnable> mRunnableCache = new SparseArray<>(5); boolean mEnabled; - OrientationListener(Context context, Handler handler, WindowManagerService service) { - super(context, handler, service); + OrientationListener(Context context, Handler handler) { + super(context, handler); } private class UpdateRunnable implements Runnable { diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index 84616c0bdc8e..aa7e6c9c80fc 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -116,10 +116,8 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal /** Notifies that the input device configuration has changed. */ @Override public void notifyConfigurationChanged() { - // TODO(multi-display): Notify proper displays that are associated with this input device. - synchronized (mService.mGlobalLock) { - mService.getDefaultDisplayContentLocked().sendNewConfiguration(); + mService.mRoot.forAllDisplays(DisplayContent::sendNewConfiguration); } synchronized (mInputDevicesReadyMonitor) { diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java index 15e078b478b8..dea83f0c00e5 100644 --- a/services/core/java/com/android/server/wm/PinnedTaskController.java +++ b/services/core/java/com/android/server/wm/PinnedTaskController.java @@ -16,20 +16,26 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ROTATION_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; + import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.app.PictureInPictureParams; import android.app.RemoteAction; import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.content.res.Resources; +import android.graphics.Matrix; +import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; -import android.util.DisplayMetrics; import android.util.Log; import android.util.Slog; -import android.view.DisplayInfo; import android.view.IPinnedTaskListener; +import android.view.SurfaceControl; +import android.window.PictureInPictureSurfaceTransaction; import java.io.PrintWriter; import java.util.ArrayList; @@ -54,6 +60,7 @@ import java.util.List; class PinnedTaskController { private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedTaskController" : TAG_WM; + private static final int DEFER_ORIENTATION_CHANGE_TIMEOUT_MS = 1000; private final WindowManagerService mService; private final DisplayContent mDisplayContent; @@ -62,8 +69,21 @@ class PinnedTaskController { private final PinnedTaskListenerDeathHandler mPinnedTaskListenerDeathHandler = new PinnedTaskListenerDeathHandler(); - /** Whether the PiP is entering or leaving. */ - private boolean mIsPipWindowingModeChanging; + /** + * Non-null if the entering PiP task will cause display rotation to change. The bounds are + * based on the new rotation. + */ + private Rect mDestRotatedBounds; + /** + * Non-null if the entering PiP task from recents animation will cause display rotation to + * change. The transaction is based on the old rotation. + */ + private PictureInPictureSurfaceTransaction mPipTransaction; + /** Whether to skip task configuration change once. */ + private boolean mFreezingTaskConfig; + /** Defer display orientation change if the PiP task is animating across orientations. */ + private boolean mDeferOrientationChanging; + private final Runnable mDeferOrientationTimeoutRunnable; private boolean mIsImeShowing; private int mImeHeight; @@ -72,16 +92,10 @@ class PinnedTaskController { private ArrayList<RemoteAction> mActions = new ArrayList<>(); private float mAspectRatio = -1f; - // Used to calculate task bounds across rotations - private final DisplayInfo mDisplayInfo = new DisplayInfo(); - // The aspect ratio bounds of the PIP. private float mMinAspectRatio; private float mMaxAspectRatio; - // Temp vars for calculation - private final DisplayMetrics mTmpMetrics = new DisplayMetrics(); - /** * Handler for the case where the listener dies. */ @@ -89,23 +103,32 @@ class PinnedTaskController { @Override public void binderDied() { - // Clean up the state if the listener dies - if (mPinnedTaskListener != null) { - mPinnedTaskListener.asBinder().unlinkToDeath(mPinnedTaskListenerDeathHandler, 0); + synchronized (mService.mGlobalLock) { + mPinnedTaskListener = null; + mFreezingTaskConfig = false; + mDeferOrientationTimeoutRunnable.run(); } - mPinnedTaskListener = null; } } PinnedTaskController(WindowManagerService service, DisplayContent displayContent) { mService = service; mDisplayContent = displayContent; - mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo()); + mDeferOrientationTimeoutRunnable = () -> { + synchronized (mService.mGlobalLock) { + if (mDeferOrientationChanging) { + continueOrientationChange(); + mService.mWindowPlacerLocked.requestTraversal(); + } + } + }; reloadResources(); } - void onConfigurationChanged() { + /** Updates the resources used by pinned controllers. */ + void onPostDisplayConfigurationChanged() { reloadResources(); + mFreezingTaskConfig = false; } /** @@ -113,7 +136,6 @@ class PinnedTaskController { */ private void reloadResources() { final Resources res = mService.mContext.getResources(); - mDisplayContent.getDisplay().getRealMetrics(mTmpMetrics); mMinAspectRatio = res.getFloat( com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio); mMaxAspectRatio = res.getFloat( @@ -143,18 +165,150 @@ class PinnedTaskController { && Float.compare(aspectRatio, mMaxAspectRatio) <= 0; } - /** Returns {@code true} if the PiP is on screen or is changing windowing mode. */ - boolean isPipActiveOrWindowingModeChanging() { - if (mIsPipWindowingModeChanging) { - return true; + /** + * Called when a fullscreen task is entering PiP with display orientation change. This is used + * to avoid flickering when running PiP animation across different orientations. + */ + void deferOrientationChangeForEnteringPipFromFullScreenIfNeeded() { + final Task topFullscreenTask = mDisplayContent.getDefaultTaskDisplayArea() + .getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN); + final ActivityRecord topFullscreen = topFullscreenTask != null + ? topFullscreenTask.topRunningActivity() : null; + if (topFullscreen == null || topFullscreen.hasFixedRotationTransform()) { + return; + } + final int rotation = mDisplayContent.rotationForActivityInDifferentOrientation( + topFullscreen); + if (rotation == ROTATION_UNDEFINED) { + return; + } + // If the next top activity will change the orientation of display, start fixed rotation to + // notify PipTaskOrganizer before it receives task appeared. And defer display orientation + // update until the new PiP bounds are set. + mDisplayContent.setFixedRotationLaunchingApp(topFullscreen, rotation); + mDeferOrientationChanging = true; + mService.mH.removeCallbacks(mDeferOrientationTimeoutRunnable); + final float animatorScale = Math.max(1, mService.getCurrentAnimatorScale()); + mService.mH.postDelayed(mDeferOrientationTimeoutRunnable, + (int) (animatorScale * DEFER_ORIENTATION_CHANGE_TIMEOUT_MS)); + } + + /** Defers orientation change while there is a top fixed rotation activity. */ + boolean shouldDeferOrientationChange() { + return mDeferOrientationChanging; + } + + /** + * Sets the bounds for {@link #startSeamlessRotationIfNeeded} if the orientation of display + * will be changed. + */ + void setEnterPipBounds(Rect bounds) { + if (!mDeferOrientationChanging) { + return; + } + mFreezingTaskConfig = true; + mDestRotatedBounds = new Rect(bounds); + continueOrientationChange(); + } + + /** + * Sets the transaction for {@link #startSeamlessRotationIfNeeded} if the orientation of display + * will be changed. This is only called when finishing recents animation with pending + * orientation change that will be handled by + * {@link DisplayContent.FixedRotationTransitionListener#onFinishRecentsAnimation}. + */ + void setEnterPipTransaction(PictureInPictureSurfaceTransaction tx) { + mFreezingTaskConfig = true; + mPipTransaction = tx; + } + + /** Called when the activity in PiP task has PiP windowing mode (at the end of animation). */ + private void continueOrientationChange() { + mDeferOrientationChanging = false; + mService.mH.removeCallbacks(mDeferOrientationTimeoutRunnable); + final WindowContainer<?> orientationSource = mDisplayContent.getLastOrientationSource(); + if (orientationSource != null && !orientationSource.isAppTransitioning()) { + mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp(); + } + } + + /** + * Resets rotation and applies scale and position to PiP task surface to match the current + * rotation of display. The final surface matrix will be replaced by PiPTaskOrganizer after it + * receives the callback of fixed rotation completion. + */ + void startSeamlessRotationIfNeeded(SurfaceControl.Transaction t) { + final Rect bounds = mDestRotatedBounds; + final PictureInPictureSurfaceTransaction pipTx = mPipTransaction; + if (bounds == null && pipTx == null) { + return; + } + final TaskDisplayArea taskArea = mDisplayContent.getDefaultTaskDisplayArea(); + final Task pinnedTask = taskArea.getRootPinnedTask(); + if (pinnedTask == null) { + return; } - final Task pinnedTask = mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask(); - return pinnedTask != null && pinnedTask.hasChild(); + + mDestRotatedBounds = null; + mPipTransaction = null; + final Rect areaBounds = taskArea.getBounds(); + if (pipTx != null) { + // The transaction from recents animation is in old rotation. So the position needs to + // be rotated. + float dx = pipTx.mPositionX; + float dy = pipTx.mPositionY; + if (pipTx.mRotation == 90) { + dx = pipTx.mPositionY; + dy = areaBounds.right - pipTx.mPositionX; + } else if (pipTx.mRotation == -90) { + dx = areaBounds.bottom - pipTx.mPositionY; + dy = pipTx.mPositionX; + } + final Matrix matrix = new Matrix(); + matrix.setScale(pipTx.mScaleX, pipTx.mScaleY); + matrix.postTranslate(dx, dy); + t.setMatrix(pinnedTask.getSurfaceControl(), matrix, new float[9]); + Slog.i(TAG, "Seamless rotation PiP tx=" + pipTx + " pos=" + dx + "," + dy); + return; + } + + final PictureInPictureParams params = pinnedTask.getPictureInPictureParams(); + final Rect sourceHintRect = params != null && params.hasSourceBoundsHint() + ? params.getSourceRectHint() + : null; + Slog.i(TAG, "Seamless rotation PiP bounds=" + bounds + " hintRect=" + sourceHintRect); + final Rect contentBounds = sourceHintRect != null && areaBounds.contains(sourceHintRect) + ? sourceHintRect : areaBounds; + final int w = contentBounds.width(); + final int h = contentBounds.height(); + final float scale = w <= h ? (float) bounds.width() / w : (float) bounds.height() / h; + final int insetLeft = (int) ((contentBounds.left - areaBounds.left) * scale + .5f); + final int insetTop = (int) ((contentBounds.top - areaBounds.top) * scale + .5f); + final Matrix matrix = new Matrix(); + matrix.setScale(scale, scale); + matrix.postTranslate(bounds.left - insetLeft, bounds.top - insetTop); + t.setMatrix(pinnedTask.getSurfaceControl(), matrix, new float[9]); + } + + /** + * Returns {@code true} to skip {@link Task#onConfigurationChanged} because it is expected that + * there will be a orientation change and a PiP configuration change. + */ + boolean isFreezingTaskConfig(Task task) { + return mFreezingTaskConfig + && task == mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask(); } - /** Sets whether a visible task is changing from or to pinned mode. */ - void setPipWindowingModeChanging(boolean isPipWindowingModeChanging) { - mIsPipWindowingModeChanging = isPipWindowingModeChanging; + /** Resets the states which were used to perform fixed rotation with PiP task. */ + void onCancelFixedRotationTransform(Task task) { + mFreezingTaskConfig = false; + mDeferOrientationChanging = false; + mDestRotatedBounds = null; + mPipTransaction = null; + if (!task.isOrganized()) { + // Force clearing Task#mForceNotOrganized because the display didn't rotate. + task.onConfigurationChanged(task.getParent().getConfiguration()); + } } /** @@ -272,6 +426,14 @@ class PinnedTaskController { void dump(String prefix, PrintWriter pw) { pw.println(prefix + "PinnedTaskController"); + if (mDeferOrientationChanging) pw.println(prefix + " mDeferOrientationChanging=true"); + if (mFreezingTaskConfig) pw.println(prefix + " mFreezingTaskConfig=true"); + if (mDestRotatedBounds != null) { + pw.println(prefix + " mPendingBounds=" + mDestRotatedBounds); + } + if (mPipTransaction != null) { + pw.println(prefix + " mPipTransaction=" + mPipTransaction); + } pw.println(prefix + " mIsImeShowing=" + mIsImeShowing); pw.println(prefix + " mImeHeight=" + mImeHeight); pw.println(prefix + " mAspectRatio=" + mAspectRatio); @@ -288,6 +450,5 @@ class PinnedTaskController { } pw.println(prefix + " ]"); } - pw.println(prefix + " mDisplayInfo=" + mDisplayInfo); } } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index e165dfa9c545..dec6460147cf 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -1146,6 +1146,11 @@ public class RecentsAnimationController implements DeathRecipient { PictureInPictureSurfaceTransaction.apply(mFinishTransaction, mTask.mSurfaceControl, pendingTransaction); mTask.setLastRecentsAnimationTransaction(mFinishTransaction); + if (mDisplayContent.isFixedRotationLaunchingApp(mTargetActivityRecord)) { + // The transaction is needed for position when rotating the display. + mDisplayContent.mPinnedTaskController.setEnterPipTransaction( + mFinishTransaction); + } mFinishTransaction = null; pendingTransaction.apply(); } else if (!mTask.isAttached()) { diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 67bc7af6dc28..1a429f88fe2e 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -55,7 +55,7 @@ import java.util.ArrayList; class RemoteAnimationController implements DeathRecipient { private static final String TAG = TAG_WITH_CLASS_NAME ? "RemoteAnimationController" : TAG_WM; - private static final long TIMEOUT_MS = 2000; + private static final long TIMEOUT_MS = 10000; private final WindowManagerService mService; private final DisplayContent mDisplayContent; diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java index cd20c8242d81..1cda8d56ddc7 100644 --- a/services/core/java/com/android/server/wm/RootDisplayArea.java +++ b/services/core/java/com/android/server/wm/RootDisplayArea.java @@ -37,7 +37,7 @@ import java.util.Map; * of the whole logical display, or a {@link DisplayAreaGroup} as the root of a partition of the * logical display. */ -class RootDisplayArea extends DisplayArea<DisplayArea> { +class RootDisplayArea extends DisplayArea.Dimmable { /** {@link Feature} that are supported in this {@link DisplayArea} hierarchy. */ List<DisplayAreaPolicyBuilder.Feature> mFeatures; diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index c81f31eb9f77..dc079880d2aa 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2657,9 +2657,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } void addStartingWindowsForVisibleActivities() { + final ArrayList<Task> addedTasks = new ArrayList<>(); forAllActivities((r) -> { - if (r.mVisibleRequested) { + final Task task = r.getTask(); + if (r.mVisibleRequested && r.mStartingData == null && !addedTasks.contains(task)) { r.showStartingWindow(true /*taskSwitch*/); + addedTasks.add(task); } }); } @@ -2810,10 +2813,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return false; } - Task getLaunchRootTask(@Nullable ActivityRecord r, - @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop) { - return getLaunchRootTask(r, options, candidateTask, onTop, null /* launchParams */, - -1 /* no realCallingPid */, -1 /* no realCallingUid */); + Task getLaunchRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options, + @Nullable Task candidateTask, boolean onTop) { + return getLaunchRootTask(r, options, candidateTask, null /* sourceTask */, onTop, + null /* launchParams */, 0 /* launchFlags */, -1 /* no realCallingPid */, + -1 /* no realCallingUid */); } /** @@ -2822,15 +2826,18 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * @param r The activity we are trying to launch. Can be null. * @param options The activity options used to the launch. Can be null. * @param candidateTask The possible task the activity might be launched in. Can be null. + * @param sourceTask The task requesting to start activity. Can be null. * @param launchParams The resolved launch params to use. + * @param launchFlags The launch flags for this launch. * @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid} * @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid} * @return The root task to use for the launch or INVALID_TASK_ID. */ Task getLaunchRootTask(@Nullable ActivityRecord r, - @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop, - @Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid, - int realCallingUid) { + @Nullable ActivityOptions options, @Nullable Task candidateTask, + @Nullable Task sourceTask, boolean onTop, + @Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags, + int realCallingPid, int realCallingUid) { int taskId = INVALID_TASK_ID; int displayId = INVALID_DISPLAY; TaskDisplayArea taskDisplayArea = null; @@ -2894,7 +2901,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Falling back to default task container taskDisplayArea = taskDisplayArea.mDisplayContent.getDefaultTaskDisplayArea(); rootTask = taskDisplayArea.getOrCreateRootTask(r, options, candidateTask, - launchParams, activityType, onTop); + sourceTask, launchParams, launchFlags, activityType, onTop); if (rootTask != null) { return rootTask; } @@ -2949,8 +2956,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - return container.getOrCreateRootTask( - r, options, candidateTask, launchParams, activityType, onTop); + return container.getOrCreateRootTask(r, options, candidateTask, sourceTask, launchParams, + launchFlags, activityType, onTop); } /** @return true if activity record is null or can be launched on provided display. */ diff --git a/services/core/java/com/android/server/wm/SnapshotStartingData.java b/services/core/java/com/android/server/wm/SnapshotStartingData.java index 2124ed6fd39f..66ae0eb9b48f 100644 --- a/services/core/java/com/android/server/wm/SnapshotStartingData.java +++ b/services/core/java/com/android/server/wm/SnapshotStartingData.java @@ -39,4 +39,9 @@ class SnapshotStartingData extends StartingData { return mService.mStartingSurfaceController.createTaskSnapshotSurface(activity, mSnapshot); } + + @Override + boolean hasImeSurface() { + return mSnapshot.hasImeSurface(); + } } diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java index a5bd797cbc86..59de43ac95a3 100644 --- a/services/core/java/com/android/server/wm/StartingData.java +++ b/services/core/java/com/android/server/wm/StartingData.java @@ -40,4 +40,9 @@ public abstract class StartingData { * {@link StartingSurface#remove} */ abstract StartingSurface createStartingSurface(ActivityRecord activity); + + /** @see android.window.TaskSnapshot#hasImeSurface() */ + boolean hasImeSurface() { + return false; + } } diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java index a9b06ca5042b..c3815c1e1796 100644 --- a/services/core/java/com/android/server/wm/StartingSurfaceController.java +++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java @@ -118,7 +118,9 @@ public class StartingSurfaceController { return null; } if (topFullscreenActivity.getWindowConfiguration().getRotation() - != taskSnapshot.getRotation()) { + != taskSnapshot.getRotation() + // Use normal rotation to avoid flickering of IME window in old orientation. + && !taskSnapshot.hasImeSurface()) { // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible // that the activity will be updated to the same rotation as the snapshot. Since // the transition is not started yet, fixed rotation transform needs to be applied diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index d56d73ad813d..c6478ee968fc 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -176,12 +176,14 @@ import android.app.servertransaction.NewIntentItem; import android.app.servertransaction.PauseActivityItem; import android.app.servertransaction.ResumeActivityItem; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; @@ -2267,7 +2269,6 @@ class Task extends WindowContainer<WindowContainer> { } if (pipChanging) { - mDisplayContent.getPinnedTaskController().setPipWindowingModeChanging(true); // If the top activity is using fixed rotation, it should be changing from PiP to // fullscreen with display orientation change. Do not notify fullscreen task organizer // because the restoration of task surface and the transformation of activity surface @@ -2276,29 +2277,15 @@ class Task extends WindowContainer<WindowContainer> { if (r != null && mDisplayContent.isFixedRotationLaunchingApp(r)) { mForceNotOrganized = true; } - } else if (mForceNotOrganized) { + } else { // If the display orientation change is done, let the corresponding task organizer take // back the control of this task. - final ActivityRecord r = topRunningActivity(); - if (r == null || !mDisplayContent.isFixedRotationLaunchingApp(r)) { - mForceNotOrganized = false; - } + mForceNotOrganized = false; } - try { - // We have 2 reasons why we need to report orientation change here. - // 1. In some cases (e.g. freeform -> fullscreen) we don't have other ways of reporting. - // 2. Report orientation as soon as possible so that the display can freeze earlier if - // the display orientation will be changed. Because the surface bounds of activity - // may have been set to fullscreen but the activity hasn't redrawn its content yet, - // the rotation animation needs to capture snapshot earlier to avoid animating from - // an intermediate state. - if (oldOrientation != getOrientation()) { - onDescendantOrientationChanged(this); - } - } finally { - if (pipChanging) { - mDisplayContent.getPinnedTaskController().setPipWindowingModeChanging(false); - } + + // Report orientation change such as changing from freeform to fullscreen. + if (oldOrientation != getOrientation()) { + onDescendantOrientationChanged(this); } saveLaunchingStateIfNeeded(); @@ -2321,6 +2308,15 @@ class Task extends WindowContainer<WindowContainer> { @Override public void onConfigurationChanged(Configuration newParentConfig) { + if (mDisplayContent != null + && mDisplayContent.mPinnedTaskController.isFreezingTaskConfig(this)) { + // It happens when animating from fullscreen to PiP with orientation change. Because + // the activity in this pinned task is in fullscreen windowing mode (see + // RootWindowContainer#moveActivityToPinnedRootTask) and the activity will be set to + // pinned mode after the animation is done, the configuration change by orientation + // change is just an intermediate state that should be ignored to avoid flickering. + return; + } // Calling Task#onConfigurationChanged() for leaf task since the ops in this method are // particularly for root tasks, like preventing bounds changes when inheriting certain // windowing mode. @@ -2840,14 +2836,13 @@ class Task extends WindowContainer<WindowContainer> { getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode); } - // Do not allow non-resizable tasks to be in a multi-window mode, unless it is in pinned - // windowing mode or supports non-resizable tasks in multi-window mode. - if (!isResizeable()) { + // Do not allow tasks not support multi window to be in a multi-window mode, unless it is in + // pinned windowing mode. + if (!supportsMultiWindow()) { final int candidateWindowingMode = windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : parentWindowingMode; if (WindowConfiguration.inMultiWindowMode(candidateWindowingMode) - && candidateWindowingMode != WINDOWING_MODE_PINNED - && !mTaskSupervisor.mService.mSupportsNonResizableMultiWindow) { + && candidateWindowingMode != WINDOWING_MODE_PINNED) { getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode( WINDOWING_MODE_FULLSCREEN); } @@ -4083,6 +4078,7 @@ class Task extends WindowContainer<WindowContainer> { info.lastActiveTime = lastActiveTime; info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription()); info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode(); + info.supportsMultiWindow = supportsMultiWindow(); info.configuration.setTo(getConfiguration()); // Update to the task's current activity type and windowing mode which may differ from the // window configuration @@ -4471,10 +4467,10 @@ class Task extends WindowContainer<WindowContainer> { pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture); pw.print(" isResizeable="); pw.println(isResizeable()); pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime); + pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); if (mForceNotOrganized) { pw.print(prefix); pw.println("mForceNotOrganized=true"); } - pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); } @Override @@ -5437,6 +5433,13 @@ class Task extends WindowContainer<WindowContainer> { // Nothing else to do if we don't have a window container yet. E.g. call from ctor. return; } + + // From fullscreen to PiP. + if (topActivity != null && currentMode == WINDOWING_MODE_FULLSCREEN + && windowingMode == WINDOWING_MODE_PINNED) { + mDisplayContent.mPinnedTaskController + .deferOrientationChangeForEnteringPipFromFullScreenIfNeeded(); + } } finally { mAtmService.continueWindowLayout(); } @@ -6676,8 +6679,30 @@ class Task extends WindowContainer<WindowContainer> { prev = null; } } - final int splashScreenThemeResId = options != null + + // TODO(185200798): Persist theme name instead of theme if + int splashScreenThemeResId = options != null ? options.getSplashScreenThemeResId() : 0; + + // User can override the splashscreen theme. The theme name is used to persist + // the setting, so if no theme is set in the ActivityOptions, we check if has + // been persisted here. + if (splashScreenThemeResId == 0) { + try { + String themeName = mAtmService.getPackageManager() + .getSplashScreenTheme(r.packageName, r.mUserId); + if (themeName != null) { + Context packageContext = mAtmService.mContext + .createPackageContext(r.packageName, 0); + splashScreenThemeResId = packageContext.getResources() + .getIdentifier(themeName, null, null); + } + } catch (RemoteException | PackageManager.NameNotFoundException + | Resources.NotFoundException ignore) { + // Just use the default theme + } + } + r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity), splashScreenThemeResId, samePackage); } @@ -7151,8 +7176,11 @@ class Task extends WindowContainer<WindowContainer> { if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" + tr.mTaskId); - mDisplayContent.prepareAppTransition(TRANSIT_TO_BACK); - mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_TO_BACK, tr); + // Skip the transition for pinned task. + if (!inPinnedWindowingMode()) { + mDisplayContent.prepareAppTransition(TRANSIT_TO_BACK); + mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_TO_BACK, tr); + } moveToBack("moveTaskToBackLocked", tr); if (inPinnedWindowingMode()) { @@ -7927,6 +7955,17 @@ class Task extends WindowContainer<WindowContainer> { private boolean mHasBeenVisible; private boolean mRemoveWithTaskOrganizer; + /** + * Records the source task that requesting to build a new task, used to determine which of + * the adjacent roots should be launch root of the new task. + */ + private Task mSourceTask; + + /** + * Records launch flags to apply when launching new task. + */ + private int mLaunchFlags; + Builder(ActivityTaskManagerService atm) { mAtmService = atm; } @@ -7936,6 +7975,16 @@ class Task extends WindowContainer<WindowContainer> { return this; } + Builder setSourceTask(Task sourceTask) { + mSourceTask = sourceTask; + return this; + } + + Builder setLaunchFlags(int launchFlags) { + mLaunchFlags = launchFlags; + return this; + } + Builder setTaskId(int taskId) { mTaskId = taskId; return this; @@ -8190,9 +8239,14 @@ class Task extends WindowContainer<WindowContainer> { tda.getRootPinnedTask().dismissPip(); } + if (mIntent != null) { + mLaunchFlags |= mIntent.getFlags(); + } + // Task created by organizer are added as root. final Task launchRootTask = mCreatedByOrganizer - ? null : tda.getLaunchRootTask(mWindowingMode, mActivityType, mActivityOptions); + ? null : tda.getLaunchRootTask(mWindowingMode, mActivityType, mActivityOptions, + mSourceTask, mLaunchFlags); if (launchRootTask != null) { // Since this task will be put into a root task, its windowingMode will be // inherited. diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 4d85e7bda900..87f685e95fe1 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -27,6 +27,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -43,7 +44,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.WindowConfiguration; -import android.content.Intent; import android.os.UserHandle; import android.util.IntArray; import android.util.Slog; @@ -133,6 +133,11 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { private final ArrayList<LaunchRootTaskDef> mLaunchRootTasks = new ArrayList<>(); /** + * A launch root task for activity launching with {@link FLAG_ACTIVITY_LAUNCH_ADJACENT} flag. + */ + private Task mLaunchAdjacentFlagRootTask; + + /** * A focusable root task that is purposely to be positioned at the top. Although the root * task may not have the topmost index, it is used as a preferred candidate to prevent being * unable to resume target root task properly when there are other focusable always-on-top @@ -1013,6 +1018,9 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { if (mPreferredTopFocusableRootTask == rootTask) { mPreferredTopFocusableRootTask = null; } + if (mLaunchAdjacentFlagRootTask == rootTask) { + mLaunchAdjacentFlagRootTask = null; + } mDisplayContent.releaseSelfIfNeeded(); onRootTaskOrderChanged(rootTask); } @@ -1047,11 +1055,11 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { * Returns an existing root task compatible with the windowing mode and activity type or * creates one if a compatible root task doesn't exist. * - * @see #getOrCreateRootTask(int, int, boolean, Intent, Task, ActivityOptions) + * @see #getOrCreateRootTask(int, int, boolean, Task, Task, ActivityOptions, int) */ Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop) { - return getOrCreateRootTask(windowingMode, activityType, onTop, null /* intent */, - null /* candidateTask */, null /* options */); + return getOrCreateRootTask(windowingMode, activityType, onTop, null /* candidateTask */, + null /* sourceTask */, null /* options */, 0 /* intent */); } /** @@ -1060,11 +1068,21 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { * For one level task, the candidate task would be reused to also be the root task or create * a new root task if no candidate task. * + * @param windowingMode The windowing mode the root task should be created in. + * @param activityType The activityType the root task should be created in. + * @param onTop If true the root task will be created at the top of the display, + * else at the bottom. + * @param candidateTask The possible task the activity might be launched in. Can be null. + * @param sourceTask The task requesting to start activity. Used to determine which of the + * adjacent roots should be launch root of the new task. Can be null. + * @param options The activity options used to the launch. Can be null. + * @param launchFlags The launch flags for this launch. + * @return The root task to use for the launch. * @see #getRootTask(int, int) - * @see #createRootTask(int, int, boolean) */ Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop, - Intent intent, Task candidateTask, ActivityOptions options) { + @Nullable Task candidateTask, @Nullable Task sourceTask, + @Nullable ActivityOptions options, int launchFlags) { // Need to pass in a determined windowing mode to see if a new root task should be created, // so use its parent's windowing mode if it is undefined. if (!alwaysCreateRootTask( @@ -1077,7 +1095,8 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { } else if (candidateTask != null) { final Task rootTask = candidateTask; final int position = onTop ? POSITION_TOP : POSITION_BOTTOM; - final Task launchRootTask = getLaunchRootTask(windowingMode, activityType, options); + final Task launchRootTask = getLaunchRootTask(windowingMode, activityType, options, + sourceTask, launchFlags); if (launchRootTask != null) { if (rootTask.getParent() == null) { @@ -1103,8 +1122,9 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { .setActivityType(activityType) .setOnTop(onTop) .setParent(this) - .setIntent(intent) + .setSourceTask(sourceTask) .setActivityOptions(options) + .setLaunchFlags(launchFlags) .build(); } @@ -1114,9 +1134,9 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { * * @see #getOrCreateRootTask(int, int, boolean) */ - Task getOrCreateRootTask(@Nullable ActivityRecord r, - @Nullable ActivityOptions options, @Nullable Task candidateTask, - @Nullable LaunchParams launchParams, int activityType, boolean onTop) { + Task getOrCreateRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options, + @Nullable Task candidateTask, @Nullable Task sourceTask, + @Nullable LaunchParams launchParams, int launchFlags, int activityType, boolean onTop) { int windowingMode = WINDOWING_MODE_UNDEFINED; if (launchParams != null) { // If launchParams isn't null, windowing mode is already resolved. @@ -1130,8 +1150,8 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { // UNDEFINED windowing mode is a valid result and means that the new root task will inherit // it's display's windowing mode. windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType); - return getOrCreateRootTask(windowingMode, activityType, onTop, null /* intent */, - candidateTask, options); + return getOrCreateRootTask(windowingMode, activityType, onTop, candidateTask, sourceTask, + options, launchFlags); } @VisibleForTesting @@ -1199,6 +1219,24 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { } } + void setLaunchAdjacentFlagRootTask(@Nullable Task adjacentFlagRootTask) { + if (adjacentFlagRootTask != null) { + if (!adjacentFlagRootTask.mCreatedByOrganizer) { + throw new IllegalArgumentException( + "Can't set not mCreatedByOrganizer as launch adjacent flag root tr=" + + adjacentFlagRootTask); + } + + if (adjacentFlagRootTask.mAdjacentTask == null) { + throw new UnsupportedOperationException( + "Can't set non-adjacent root as launch adjacent flag root tr=" + + adjacentFlagRootTask); + } + } + + mLaunchAdjacentFlagRootTask = adjacentFlagRootTask; + } + private @Nullable LaunchRootTaskDef getLaunchRootTaskDef(Task rootTask) { LaunchRootTaskDef def = null; for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) { @@ -1209,7 +1247,9 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { return def; } - Task getLaunchRootTask(int windowingMode, int activityType, ActivityOptions options) { + @Nullable + Task getLaunchRootTask(int windowingMode, int activityType, @Nullable ActivityOptions options, + @Nullable Task sourceTask, int launchFlags) { // Try to use the launch root task in options if available. if (options != null) { final Task launchRootTask = Task.fromWindowContainerToken(options.getLaunchRootTask()); @@ -1219,9 +1259,30 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { } } + // Use launch-adjacent-flag-root if launching with launch-adjacent flag. + if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0 + && mLaunchAdjacentFlagRootTask != null) { + // If the adjacent launch is coming from the same root, launch to adjacent root instead. + if (sourceTask != null + && sourceTask.getRootTask().mTaskId == mLaunchAdjacentFlagRootTask.mTaskId + && mLaunchAdjacentFlagRootTask.mAdjacentTask != null) { + return mLaunchAdjacentFlagRootTask.mAdjacentTask; + } else { + return mLaunchAdjacentFlagRootTask; + } + } + for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) { if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) { - return mLaunchRootTasks.get(i).task; + final Task launchRootTask = mLaunchRootTasks.get(i).task; + // Return the focusable root task for improving the UX with staged split screen. + final Task adjacentRootTask = launchRootTask != null + ? launchRootTask.mAdjacentTask : null; + if (adjacentRootTask != null && adjacentRootTask.isFocusedRootTaskOnDisplay()) { + return adjacentRootTask; + } else { + return launchRootTask; + } } } return null; @@ -1963,7 +2024,11 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { // Reparent task to corresponding launch root or display area. final WindowContainer launchRoot = task.supportsSplitScreenWindowingMode() ? toDisplayArea.getLaunchRootTask( - task.getWindowingMode(), task.getActivityType(), null /* options */) + task.getWindowingMode(), + task.getActivityType(), + null /* options */, + null /* sourceTask */, + 0 /* launchFlags */) : null; task.reparent(launchRoot == null ? toDisplayArea : launchRoot, POSITION_TOP); diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index 625cff340912..0bc799996abb 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -292,7 +292,8 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { mSupervisor.mRootWindowContainer.resolveActivityType(root, options, task); display.forAllTaskDisplayAreas(displayArea -> { final Task launchRoot = displayArea.getLaunchRootTask( - resolvedMode, activityType, null /* ActivityOptions */); + resolvedMode, activityType, null /* ActivityOptions */, + null /* sourceTask*/, 0 /* launchFlags */); if (launchRoot == null) { return false; } @@ -611,7 +612,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { private boolean shouldLaunchUnresizableAppInFreeform(ActivityRecord activity, TaskDisplayArea displayArea) { - if (!mSupervisor.mService.mSupportsNonResizableMultiWindow || activity.isResizeable()) { + if (!activity.supportsFreeform() || activity.isResizeable()) { return false; } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index bea733b0267e..b1c7e196b70c 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -37,6 +37,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION; +import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; @@ -2696,7 +2697,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< @Nullable ArrayList<WindowContainer> sources) { final Task task = asTask(); if (task != null && !enter && !task.isHomeOrRecentsRootTask()) { - mDisplayContent.showImeScreenshot(); + final InsetsControlTarget imeTarget = mDisplayContent.getImeTarget(IME_TARGET_LAYERING); + final boolean isImeLayeringTarget = imeTarget != null && imeTarget.getWindow() != null + && imeTarget.getWindow().getTask() == task; + // Attach and show the IME screenshot when the task is the IME target and performing + // task closing transition to the next task. + if (isImeLayeringTarget && AppTransition.isTaskCloseTransitOld(transit)) { + mDisplayContent.showImeScreenshot(); + } } final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp, transit, enter, isVoiceInteraction); diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java index 015a0fb30a5b..a5ebf9ac74b9 100644 --- a/services/core/java/com/android/server/wm/WindowManagerConstants.java +++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java @@ -49,10 +49,6 @@ final class WindowManagerConstants { static final String KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS = "system_gesture_exclusion_log_debounce_millis"; - // Enable logging from the sensor which publishes accel and gyro data generating a rotation - // event - private static final String KEY_RAW_SENSOR_LOGGING_ENABLED = "raw_sensor_logging_enabled"; - private static final int MIN_GESTURE_EXCLUSION_LIMIT_DP = 200; /** @see #KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS */ @@ -62,8 +58,6 @@ final class WindowManagerConstants { /** @see AndroidDeviceConfig#KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE */ boolean mSystemGestureExcludedByPreQStickyImmersive; - boolean mRawSensorLoggingEnabled; - private final WindowManagerGlobalLock mGlobalLock; private final Runnable mUpdateSystemGestureExclusionCallback; private final DeviceConfigInterface mDeviceConfig; @@ -139,9 +133,6 @@ final class WindowManagerConstants { case KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS: updateSystemGestureExclusionLogDebounceMillis(); break; - case KEY_RAW_SENSOR_LOGGING_ENABLED: - updateRawSensorDataLoggingEnabled(); - break; default: break; } @@ -167,12 +158,6 @@ final class WindowManagerConstants { KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false); } - private void updateRawSensorDataLoggingEnabled() { - mRawSensorLoggingEnabled = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_WINDOW_MANAGER, - KEY_RAW_SENSOR_LOGGING_ENABLED, false); - } - void dump(PrintWriter pw) { pw.println("WINDOW MANAGER CONSTANTS (dumpsys window constants):"); @@ -182,8 +167,6 @@ final class WindowManagerConstants { pw.print("="); pw.println(mSystemGestureExclusionLimitDp); pw.print(" "); pw.print(KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE); pw.print("="); pw.println(mSystemGestureExcludedByPreQStickyImmersive); - pw.print(" "); pw.print(KEY_RAW_SENSOR_LOGGING_ENABLED); - pw.print("="); pw.println(mRawSensorLoggingEnabled); pw.println(); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 3d84ca7212f1..dfc677278847 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -451,8 +451,7 @@ public class WindowManagerService extends IWindowManager.Stub private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000; - @VisibleForTesting - WindowManagerConstants mConstants; + final WindowManagerConstants mConstants; final WindowTracing mWindowTracing; @@ -5554,11 +5553,6 @@ public class WindowManagerService extends IWindowManager.Stub mBlurController.unregisterCrossWindowBlurEnabledListener(listener); } - @Override - public void setForceCrossWindowBlurDisabled(boolean disable) { - mBlurController.setForceCrossWindowBlurDisabled(disable); - } - // ------------------------------------------------------------- // Internals // ------------------------------------------------------------- @@ -6298,7 +6292,7 @@ public class WindowManagerService extends IWindowManager.Stub } }); pw.print(" mInTouchMode="); pw.println(mInTouchMode); - pw.print(" mBlurEnabled="); pw.println(mBlurController.mBlurEnabled); + pw.print(" mBlurEnabled="); pw.println(mBlurController.getBlurEnabled()); pw.print(" mLastDisplayFreezeDuration="); TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw); if ( mLastFinishedFreezeSource != null) { @@ -8129,6 +8123,16 @@ public class WindowManagerService extends IWindowManager.Stub return; } + if (mRecentsAnimationController != null + && mRecentsAnimationController.getTargetAppMainWindow() == touchedWindow) { + // If there is an active recents animation and touched window is the target, then ignore + // the touch. The target already handles touches using its own input monitor and we + // don't want to trigger any lifecycle changes from focusing another window. + // TODO(b/186770026): We should remove this once we support multiple resumed activities + // while in overview + return; + } + ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "onPointerDownOutsideFocusLocked called on %s", touchedWindow); final DisplayContent displayContent = touchedWindow.getDisplayContent(); diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 1b578d1d452c..4dc60070d6ec 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -31,6 +31,7 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ShellCommand; import android.os.UserHandle; +import android.provider.Settings; import android.util.DisplayMetrics; import android.util.Pair; import android.view.Display; @@ -216,7 +217,7 @@ public class WindowManagerShellCommand extends ShellCommand { String arg = getNextArg(); if (arg == null) { pw.println("Blur supported on device: " + CROSS_WINDOW_BLUR_SUPPORTED); - pw.println("Blur enabled: " + mInternal.mBlurController.mBlurEnabled); + pw.println("Blur enabled: " + mInternal.mBlurController.getBlurEnabled()); return 0; } @@ -235,7 +236,9 @@ public class WindowManagerShellCommand extends ShellCommand { return -1; } - mInterface.setForceCrossWindowBlurDisabled(disableBlur); + Settings.Global.putInt(mInternal.mContext.getContentResolver(), + Settings.Global.DISABLE_WINDOW_BLURS, disableBlur ? 1 : 0); + return 0; } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 9382b8eed0b8..c29211f3bb65 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -22,6 +22,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; @@ -320,6 +321,26 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } break; } + case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: { + final WindowContainer wc = WindowContainer.fromBinder( + hop.getContainer()); + final Task task = wc != null ? wc.asTask() : null; + if (task == null) { + throw new IllegalArgumentException("Cannot set " + + "non-task as launch root: " + wc); + } else if (!task.mCreatedByOrganizer) { + throw new UnsupportedOperationException("Cannot set " + + "non-organized task as adjacent flag root: " + wc); + } else if (task.mAdjacentTask == null) { + throw new UnsupportedOperationException("Cannot set " + + "non-adjacent task as adjacent flag root: " + wc); + } + + final boolean clearRoot = hop.getToTop(); + task.getDisplayArea() + .setLaunchAdjacentFlagRootTask(clearRoot ? null : task); + break; + } case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId); break; @@ -491,7 +512,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub Rect enterPipBounds = c.getEnterPipBounds(); if (enterPipBounds != null) { - mService.mTaskSupervisor.updatePictureInPictureMode(tr, enterPipBounds, true); + tr.mDisplayContent.mPinnedTaskController.setEnterPipBounds(enterPipBounds); } return effects; diff --git a/services/core/java/com/android/server/wm/WindowOrientationListener.java b/services/core/java/com/android/server/wm/WindowOrientationListener.java index be6847aba12a..3e099fb84f03 100644 --- a/services/core/java/com/android/server/wm/WindowOrientationListener.java +++ b/services/core/java/com/android/server/wm/WindowOrientationListener.java @@ -85,7 +85,6 @@ public abstract class WindowOrientationListener { private int mCurrentRotation = -1; private final Context mContext; - private final WindowManagerConstants mConstants; private final Object mLock = new Object(); @@ -94,11 +93,9 @@ public abstract class WindowOrientationListener { * * @param context for the WindowOrientationListener. * @param handler Provides the Looper for receiving sensor updates. - * @param wmService WindowManagerService to read the device config from. */ - public WindowOrientationListener( - Context context, Handler handler, WindowManagerService wmService) { - this(context, handler, wmService, SensorManager.SENSOR_DELAY_UI); + public WindowOrientationListener(Context context, Handler handler) { + this(context, handler, SensorManager.SENSOR_DELAY_UI); } /** @@ -115,10 +112,9 @@ public abstract class WindowOrientationListener { * This constructor is private since no one uses it. */ private WindowOrientationListener( - Context context, Handler handler, WindowManagerService wmService, int rate) { + Context context, Handler handler, int rate) { mContext = context; mHandler = handler; - mConstants = wmService.mConstants; mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); mRate = rate; List<Sensor> l = mSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION); @@ -1134,16 +1130,11 @@ public abstract class WindowOrientationListener { return; } - // Log raw sensor rotation. - if (evaluateRotationChangeLocked() >= 0) { - if (mConstants.mRawSensorLoggingEnabled) { - FrameworkStatsLog.write( - FrameworkStatsLog.DEVICE_ROTATED, - event.timestamp, - rotationToLogEnum(reportedRotation), - FrameworkStatsLog.DEVICE_ROTATED__ROTATION_EVENT_TYPE__ACTUAL_EVENT); - } - } + FrameworkStatsLog.write( + FrameworkStatsLog.DEVICE_ROTATED, + event.timestamp, + rotationToLogEnum(reportedRotation), + FrameworkStatsLog.DEVICE_ROTATED__ROTATION_EVENT_TYPE__ACTUAL_EVENT); if (isRotationResolverEnabled()) { if (mRotationResolverService == null) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 83f74cd49b59..2e8d4cd4e7f8 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -906,6 +906,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // The transform of its surface is handled by fixed rotation. return; } + final Task task = getTask(); + if (task != null && task.inPinnedWindowingMode()) { + // It is handled by PinnedTaskController. Note that the windowing mode of activity + // and windows may still be fullscreen. + return; + } if (mPendingSeamlessRotate != null) { oldRotation = mPendingSeamlessRotate.getOldRotation(); @@ -1259,7 +1265,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mHaveFrame = true; final Task task = getTask(); - final boolean isFullscreenAndFillsDisplay = !inMultiWindowMode() && matchesDisplayBounds(); + final boolean isFullscreenAndFillsArea = !inMultiWindowMode() && matchesDisplayAreaBounds(); final boolean windowsAreFloating = task != null && task.isFloating(); final DisplayContent dc = getDisplayContent(); final DisplayInfo displayInfo = getDisplayInfo(); @@ -1284,7 +1290,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP : isImeLayeringTarget(); final boolean isImeTarget = imeWin != null && imeWin.isVisibleNow() && isInputMethodAdjustTarget; - if (isFullscreenAndFillsDisplay || layoutInParentFrame()) { + if (isFullscreenAndFillsArea || layoutInParentFrame()) { // We use the parent frame as the containing frame for fullscreen and child windows windowFrames.mContainingFrame.set(windowFrames.mParentFrame); layoutDisplayFrame = windowFrames.mDisplayFrame; @@ -2266,19 +2272,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP && mWindowFrames.mFrame.bottom >= displayInfo.appHeight; } - private boolean matchesDisplayBounds() { - final Rect displayBounds = mToken.getFixedRotationTransformDisplayBounds(); - if (displayBounds != null) { + boolean matchesDisplayAreaBounds() { + final Rect rotatedDisplayBounds = mToken.getFixedRotationTransformDisplayBounds(); + if (rotatedDisplayBounds != null) { // If the rotated display bounds are available, the window bounds are also rotated. - return displayBounds.equals(getBounds()); + return rotatedDisplayBounds.equals(getBounds()); } - return getDisplayContent().getBounds().equals(getBounds()); - } - - boolean matchesDisplayAreaBounds() { final DisplayArea displayArea = getDisplayArea(); if (displayArea == null) { - return matchesDisplayBounds(); + return getDisplayContent().getBounds().equals(getBounds()); } return displayArea.getBounds().equals(getBounds()); } @@ -2292,6 +2294,27 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } @Override + public void onConfigurationChanged(Configuration newParentConfig) { + if (getDisplayContent().getImeTarget(IME_TARGET_INPUT) != this && !isImeLayeringTarget()) { + super.onConfigurationChanged(newParentConfig); + return; + } + + mTempConfiguration.setTo(getConfiguration()); + super.onConfigurationChanged(newParentConfig); + final boolean windowConfigChanged = mTempConfiguration.windowConfiguration + .diff(newParentConfig.windowConfiguration, false) != 0; + + // When the window configuration changed, we need to update the IME control target in + // case the app may lose the IME inets control when exiting from split-screen mode, or the + // IME parent may failed to attach to the app during rotating the screen. + // See DisplayContent#isImeAttachedToApp, DisplayContent#isImeControlledByApp + if (windowConfigChanged) { + getDisplayContent().updateImeControlTarget(); + } + } + + @Override void onMergedOverrideConfigurationChanged() { super.onMergedOverrideConfigurationChanged(); mLastConfigReportedToClient = false; @@ -5348,7 +5371,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } private boolean shouldDrawBlurBehind() { - return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 && mWmService.mBlurController.mBlurEnabled; + return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 + && mWmService.mBlurController.getBlurEnabled(); } /** diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS index d076434e7d90..51bc99a693ff 100644 --- a/services/core/jni/OWNERS +++ b/services/core/jni/OWNERS @@ -27,3 +27,4 @@ per-file com_android_server_se_* = file:/core/java/android/se/OWNERS per-file com_android_server_security_* = file:/core/java/android/security/OWNERS per-file com_android_server_tv_* = file:/media/java/android/media/tv/OWNERS per-file com_android_server_vibrator_* = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file com_android_server_am_CachedAppOptimizer.cpp = timmurray@google.com, edgararriaga@google.com, dualli@google.com, carmenjackson@google.com, philipcuadra@google.com
\ No newline at end of file diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 64cdfa65f9c5..24f73c3ac54c 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -108,7 +108,6 @@ import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; -import static android.provider.Settings.Global.PRIVATE_DNS_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; import static android.provider.Telephony.Carriers.DPC_URI; @@ -227,6 +226,7 @@ import android.location.LocationManager; import android.media.AudioManager; import android.media.IAudioService; import android.net.ConnectivityManager; +import android.net.ConnectivitySettingsManager; import android.net.IIpConnectivityMetrics; import android.net.ProxyInfo; import android.net.Uri; @@ -745,6 +745,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Slogf.wtfStack(LOG_TAG, "Not holding DPMS lock."); } + /** + * Calls wtfStack() if called with the DPMS lock held. + */ + private void wtfIfInLock() { + if (Thread.holdsLock(mLockDoNoUseDirectly)) { + Slogf.wtfStack(LOG_TAG, "Shouldn't be called with DPMS lock held"); + } + } + @VisibleForTesting final TransferOwnershipMetadataManager mTransferOwnershipMetadataManager; @@ -874,6 +883,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { // Check whether the user is affiliated, *before* removing its data. boolean isRemovedUserAffiliated = isUserAffiliatedWithDeviceLocked(userHandle); + if (isProfileOwnerOfOrganizationOwnedDevice(userHandle)) { + // Disable network and security logging + mInjector.securityLogSetLoggingEnabledProperty(false); + mSecurityLogMonitor.stop(); + setNetworkLoggingActiveInternal(false); + } removeUserData(userHandle); if (!isRemovedUserAffiliated) { // We discard the logs when unaffiliated users are deleted (so that the @@ -4507,8 +4522,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(parentUser); final List<PasswordValidationError> passwordValidationErrors = - PasswordMetrics.validatePasswordMetrics( - minMetrics, complexity, false, metrics); + PasswordMetrics.validatePasswordMetrics(minMetrics, complexity, metrics); isSufficient = passwordValidationErrors.isEmpty(); } DevicePolicyEventLogger @@ -4585,7 +4599,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { maxRequiredComplexity = Math.max(maxRequiredComplexity, admin.mPasswordComplexity); } return PasswordMetrics.validatePasswordMetrics(PasswordMetrics.merge(adminMetrics), - maxRequiredComplexity, false, metrics).isEmpty(); + maxRequiredComplexity, metrics).isEmpty(); } } @@ -4621,8 +4635,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final int complexity = getAggregatedPasswordComplexityLocked(userId); PasswordMetrics minMetrics = getPasswordMinimumMetricsUnchecked(userId); final List<PasswordValidationError> passwordValidationErrors = - PasswordMetrics.validatePasswordMetrics( - minMetrics, complexity, false, metrics); + PasswordMetrics.validatePasswordMetrics(minMetrics, complexity, metrics); return passwordValidationErrors.isEmpty(); } @@ -4969,8 +4982,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // TODO: Consider changing validation API to take LockscreenCredential. if (password.isEmpty()) { validationErrors = PasswordMetrics.validatePasswordMetrics( - minMetrics, complexity, isPin, - new PasswordMetrics(CREDENTIAL_TYPE_NONE)); + minMetrics, complexity, new PasswordMetrics(CREDENTIAL_TYPE_NONE)); } else { // TODO(b/120484642): remove getBytes() below validationErrors = PasswordMetrics.validatePassword( @@ -8141,8 +8153,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkArgument(admin != null); final CallerIdentity caller = getCallerIdentity(); + // Cannot be called while holding the lock: + final boolean hasIncompatibleAccountsOrNonAdb = + hasIncompatibleAccountsOrNonAdbNoLock(caller, userId, admin); synchronized (getLockObject()) { - enforceCanSetDeviceOwnerLocked(caller, admin, userId); + enforceCanSetDeviceOwnerLocked(caller, admin, userId, hasIncompatibleAccountsOrNonAdb); Preconditions.checkArgument(isPackageInstalledForUser(admin.getPackageName(), userId), "Invalid component " + admin + " for device owner"); final ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(admin, userId); @@ -8537,13 +8552,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkArgument(who != null); final CallerIdentity caller = getCallerIdentity(); + // Cannot be called while holding the lock: + final boolean hasIncompatibleAccountsOrNonAdb = + hasIncompatibleAccountsOrNonAdbNoLock(caller, userHandle, who); synchronized (getLockObject()) { - enforceCanSetProfileOwnerLocked(caller, who, userHandle); - Preconditions.checkArgument(isPackageInstalledForUser(who.getPackageName(), userHandle), - "Component " + who + " not installed for userId:" + userHandle); + enforceCanSetProfileOwnerLocked( + caller, who, userHandle, hasIncompatibleAccountsOrNonAdb); final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); - Preconditions.checkArgument(admin != null && !getUserData( - userHandle).mRemovingAdmins.contains(who), "Not active admin: " + who); + Preconditions.checkArgument( + isPackageInstalledForUser(who.getPackageName(), userHandle) + && admin != null + && !getUserData(userHandle).mRemovingAdmins.contains(who), + "Not active admin: " + who); final int parentUserId = getProfileParentId(userHandle); // When trying to set a profile owner on a new user, it may be that this user is @@ -8883,17 +8903,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public ComponentName getProfileOwnerAsUser(int userHandle) { + public ComponentName getProfileOwnerAsUser(int userId) { if (!mHasFeature) { return null; } - Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId"); + Preconditions.checkArgumentNonnegative(userId, "Invalid userId"); - final CallerIdentity caller = getCallerIdentity(); - Preconditions.checkCallAuthorization(hasCrossUsersPermission(caller, userHandle)); + CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization(hasCrossUsersPermission(caller, userId)); synchronized (getLockObject()) { - return mOwners.getProfileOwnerComponent(userHandle); + return mOwners.getProfileOwnerComponent(userId); } } @@ -9117,15 +9137,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } /** - * Calls wtfStack() if called with the DPMS lock held. - */ - private void wtfIfInLock() { - if (Thread.holdsLock(this)) { - Slogf.wtfStack(LOG_TAG, "Shouldn't be called with DPMS lock held"); - } - } - - /** * The profile owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS * permission. * The profile owner can only be set before the user setup phase has completed, @@ -9133,8 +9144,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * - SYSTEM_UID * - adb unless hasIncompatibleAccountsOrNonAdb is true. */ - private void enforceCanSetProfileOwnerLocked(CallerIdentity caller, - @Nullable ComponentName owner, int userHandle) { + private void enforceCanSetProfileOwnerLocked( + CallerIdentity caller, @Nullable ComponentName owner, int userHandle, + boolean hasIncompatibleAccountsOrNonAdb) { UserInfo info = getUserInfo(userHandle); if (info == null) { // User doesn't exist. @@ -9154,7 +9166,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } if (isAdb(caller)) { if ((mIsWatch || hasUserSetupCompleted(userHandle)) - && hasIncompatibleAccountsOrNonAdbNoLock(caller, userHandle, owner)) { + && hasIncompatibleAccountsOrNonAdb) { throw new IllegalStateException("Not allowed to set the profile owner because " + "there are already some accounts on the profile"); } @@ -9191,8 +9203,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS * permission. */ - private void enforceCanSetDeviceOwnerLocked(CallerIdentity caller, - @Nullable ComponentName owner, @UserIdInt int deviceOwnerUserId) { + private void enforceCanSetDeviceOwnerLocked( + CallerIdentity caller, @Nullable ComponentName owner, @UserIdInt int deviceOwnerUserId, + boolean hasIncompatibleAccountsOrNonAdb) { if (!isAdb(caller)) { Preconditions.checkCallAuthorization( hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)); @@ -9200,8 +9213,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final int code = checkDeviceOwnerProvisioningPreConditionLocked(owner, /* deviceOwnerUserId= */ deviceOwnerUserId, /* callingUserId*/ caller.getUserId(), - isAdb(caller), - hasIncompatibleAccountsOrNonAdbNoLock(caller, deviceOwnerUserId, owner)); + isAdb(caller), hasIncompatibleAccountsOrNonAdb); if (code != CODE_OK) { throw new IllegalStateException( computeProvisioningErrorString(code, deviceOwnerUserId)); @@ -9345,19 +9357,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { public List<UserHandle> listForegroundAffiliatedUsers() { checkIsDeviceOwner(getCallerIdentity()); - int userId = mInjector.binderWithCleanCallingIdentity(() -> getCurrentForegroundUserId()); - - boolean isAffiliated; - synchronized (getLockObject()) { - isAffiliated = isUserAffiliatedWithDeviceLocked(userId); - } + return mInjector.binderWithCleanCallingIdentity(() -> { + int userId = getCurrentForegroundUserId(); + boolean isAffiliated; + synchronized (getLockObject()) { + isAffiliated = isUserAffiliatedWithDeviceLocked(userId); + } - if (!isAffiliated) return Collections.emptyList(); + if (!isAffiliated) return Collections.emptyList(); - List<UserHandle> users = new ArrayList<>(1); - users.add(UserHandle.of(userId)); + List<UserHandle> users = new ArrayList<>(1); + users.add(UserHandle.of(userId)); - return users; + return users; + }); } protected int getProfileParentId(int userHandle) { @@ -11926,17 +11939,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final CallerIdentity caller = getCallerIdentity(who); Preconditions.checkCallAuthorization(isDeviceOwner(caller)); + UserHandle userHandle = caller.getUserHandle(); + if (mIsAutomotive) { + Slogf.v(LOG_TAG, "setLocationEnabled(%s, %b): ignoring for user %s on automotive build", + who.flattenToShortString(), locationEnabled, userHandle); + return; + } + mInjector.binderWithCleanCallingIdentity(() -> { boolean wasLocationEnabled = mInjector.getLocationManager().isLocationEnabledForUser( - caller.getUserHandle()); - mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled, - caller.getUserHandle()); + userHandle); + Slogf.v(LOG_TAG, "calling locationManager.setLocationEnabledForUser(%b, %s)", + locationEnabled, userHandle); + mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled, userHandle); // make a best effort to only show the notification if the admin is actually enabling // location. this is subject to race conditions with settings changes, but those are // unlikely to realistically interfere if (locationEnabled && !wasLocationEnabled) { - showLocationSettingsEnabledNotification(caller.getUserHandle()); + showLocationSettingsEnabledNotification(userHandle); } }); @@ -13306,12 +13327,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final CallerIdentity caller = getCallerIdentity(); final long ident = mInjector.binderClearCallingIdentity(); try { - final int uidForPackage = mInjector.getPackageManager().getPackageUidAsUser( - packageName, caller.getUserId()); - Preconditions.checkArgument(caller.getUid() == uidForPackage, + final List<String> callerUidPackageNames = Arrays.asList( + mInjector.getPackageManager().getPackagesForUid(caller.getUid())); + Preconditions.checkArgument(callerUidPackageNames.contains(packageName), "Caller uid doesn't match the one for the provided package."); - } catch (NameNotFoundException e) { - throw new IllegalArgumentException("Invalid package provided " + packageName, e); } finally { mInjector.binderRestoreCallingIdentity(ident); } @@ -14111,7 +14130,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private boolean isUserAffiliatedWithDeviceLocked(int userId) { + private boolean isUserAffiliatedWithDeviceLocked(@UserIdInt int userId) { if (!mOwners.hasDeviceOwner()) { return false; } @@ -15692,12 +15711,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return context.getResources().getString(R.string.config_managed_provisioning_package); } - private void putPrivateDnsSettings(@Nullable String mode, @Nullable String host) { + private void putPrivateDnsSettings(int mode, @Nullable String host) { // Set Private DNS settings using system permissions, as apps cannot write // to global settings. mInjector.binderWithCleanCallingIdentity(() -> { - mInjector.settingsGlobalPutString(PRIVATE_DNS_MODE, mode); - mInjector.settingsGlobalPutString(PRIVATE_DNS_SPECIFIER, host); + ConnectivitySettingsManager.setPrivateDnsMode(mContext, mode); + ConnectivitySettingsManager.setPrivateDnsHostname(mContext, host); }); } @@ -15717,7 +15736,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { throw new IllegalArgumentException( "Host provided for opportunistic mode, but is not needed."); } - putPrivateDnsSettings(ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, null); + putPrivateDnsSettings(ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, + null); return PRIVATE_DNS_SET_NO_ERROR; case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: if (TextUtils.isEmpty(privateDnsHost) @@ -15729,7 +15749,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Connectivity check will have been performed in the DevicePolicyManager before // the call here. putPrivateDnsSettings( - ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, + ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, privateDnsHost); return PRIVATE_DNS_SET_NO_ERROR; default: @@ -15747,13 +15767,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final CallerIdentity caller = getCallerIdentity(who); Preconditions.checkCallAuthorization(isDeviceOwner(caller)); - final String currentMode = ConnectivityManager.getPrivateDnsMode(mContext); + final int currentMode = ConnectivitySettingsManager.getPrivateDnsMode(mContext); switch (currentMode) { - case ConnectivityManager.PRIVATE_DNS_MODE_OFF: + case ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF: return PRIVATE_DNS_MODE_OFF; - case ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC: + case ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC: return PRIVATE_DNS_MODE_OPPORTUNISTIC; - case ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: + case ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; } @@ -16774,7 +16794,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { provisioningParams.isKeepAccountMigrated(), callerPackage); if (provisioningParams.isOrganizationOwnedProvisioning()) { - setProfileOwnerOnOrgOwnedDeviceState(admin, userInfo.id, caller.getUserId()); + synchronized (getLockObject()) { + markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id); + } } return userInfo.getUserHandle(); @@ -17006,22 +17028,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private void setProfileOwnerOnOrgOwnedDeviceState( - ComponentName admin, @UserIdInt int profileId, @UserIdInt int parentUserId) { - synchronized (getLockObject()) { - markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, profileId); - } - restrictRemovalOfManagedProfile(parentUserId); - } - - private void restrictRemovalOfManagedProfile(@UserIdInt int parentUserId) { - final UserHandle parentUserHandle = UserHandle.of(parentUserId); - mUserManager.setUserRestriction( - UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, - /* value= */ true, - parentUserHandle); - } - @Override public void provisionFullyManagedDevice( @NonNull FullyManagedDeviceProvisioningParams provisioningParams, diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java index 285ecfb6b478..a2db6aaca3df 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java @@ -15,8 +15,12 @@ */ package com.android.server.devicepolicy; +import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; import android.os.ShellCommand; +import android.os.SystemClock; +import android.os.UserHandle; import com.android.server.devicepolicy.Owners.OwnerDto; @@ -32,8 +36,23 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { private static final String CMD_SET_SAFE_OPERATION = "set-operation-safe"; private static final String CMD_LIST_OWNERS = "list-owners"; private static final String CMD_LIST_POLICY_EXEMPT_APPS = "list-policy-exempt-apps"; + private static final String CMD_SET_ACTIVE_ADMIN = "set-active-admin"; + private static final String CMD_SET_DEVICE_OWNER = "set-device-owner"; + private static final String CMD_SET_PROFILE_OWNER = "set-profile-owner"; + private static final String CMD_REMOVE_ACTIVE_ADMIN = "remove-active-admin"; + private static final String CMD_CLEAR_FREEZE_PERIOD_RECORD = "clear-freeze-period-record"; + private static final String CMD_FORCE_NETWORK_LOGS = "force-network-logs"; + private static final String CMD_FORCE_SECURITY_LOGS = "force-security-logs"; + private static final String CMD_MARK_PO_ON_ORG_OWNED_DEVICE = + "mark-profile-owner-on-organization-owned-device"; + + private static final String USER_OPTION = "--user"; + private static final String NAME_OPTION = "--name"; private final DevicePolicyManagerService mService; + private int mUserId = UserHandle.USER_SYSTEM; + private String mName = ""; + private ComponentName mComponent; DevicePolicyManagerServiceShellCommand(DevicePolicyManagerService service) { mService = Objects.requireNonNull(service); @@ -41,7 +60,7 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { @Override public void onHelp() { - try (PrintWriter pw = getOutPrintWriter();) { + try (PrintWriter pw = getOutPrintWriter()) { pw.printf("DevicePolicyManager Service (device_policy) commands:\n\n"); showHelp(pw); } @@ -52,7 +71,7 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { if (cmd == null) { return handleDefaultCommands(cmd); } - try (PrintWriter pw = getOutPrintWriter();) { + try (PrintWriter pw = getOutPrintWriter()) { switch (cmd) { case CMD_IS_SAFE_OPERATION: return runIsSafeOperation(pw); @@ -64,6 +83,22 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { return runListOwners(pw); case CMD_LIST_POLICY_EXEMPT_APPS: return runListPolicyExemptApps(pw); + case CMD_SET_ACTIVE_ADMIN: + return runSetActiveAdmin(pw); + case CMD_SET_DEVICE_OWNER: + return runSetDeviceOwner(pw); + case CMD_SET_PROFILE_OWNER: + return runSetProfileOwner(pw); + case CMD_REMOVE_ACTIVE_ADMIN: + return runRemoveActiveAdmin(pw); + case CMD_CLEAR_FREEZE_PERIOD_RECORD: + return runClearFreezePeriodRecord(pw); + case CMD_FORCE_NETWORK_LOGS: + return runForceNetworkLogs(pw); + case CMD_FORCE_SECURITY_LOGS: + return runForceSecurityLogs(pw); + case CMD_MARK_PO_ON_ORG_OWNED_DEVICE: + return runMarkProfileOwnerOnOrganizationOwnedDevice(pw); default: return onInvalidCommand(pw, cmd); } @@ -75,7 +110,7 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { return 0; } - pw.println("Usage: "); + pw.printf("Usage: \n"); showHelp(pw); return -1; } @@ -94,6 +129,37 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { pw.printf(" Lists the device / profile owners per user \n\n"); pw.printf(" %s\n", CMD_LIST_POLICY_EXEMPT_APPS); pw.printf(" Lists the apps that are exempt from policies\n\n"); + pw.printf(" %s [ %s <USER_ID> | current ] <COMPONENT>\n", + CMD_SET_ACTIVE_ADMIN, USER_OPTION); + pw.printf(" Sets the given component as active admin for an existing user.\n\n"); + pw.printf(" %s [ %s <USER_ID> | current *EXPERIMENTAL* ] [ %s <NAME> ] " + + "<COMPONENT>\n", CMD_SET_DEVICE_OWNER, USER_OPTION, NAME_OPTION); + pw.printf(" Sets the given component as active admin, and its package as device owner." + + "\n\n"); + pw.printf(" %s [ %s <USER_ID> | current ] [ %s <NAME> ] <COMPONENT>\n", + CMD_SET_PROFILE_OWNER, USER_OPTION, NAME_OPTION); + pw.printf(" Sets the given component as active admin and profile owner for an existing " + + "user.\n\n"); + pw.printf(" %s [ %s <USER_ID> | current ] [ %s <NAME> ] <COMPONENT>\n", + CMD_REMOVE_ACTIVE_ADMIN, USER_OPTION, NAME_OPTION); + pw.printf(" Disables an active admin, the admin must have declared android:testOnly in " + + "the application in its manifest. This will also remove device and profile " + + "owners.\n\n"); + pw.printf(" %s\n", CMD_CLEAR_FREEZE_PERIOD_RECORD); + pw.printf(" Clears framework-maintained record of past freeze periods that the device " + + "went through. For use during feature development to prevent triggering " + + "restriction on setting freeze periods.\n\n"); + pw.printf(" %s\n", CMD_FORCE_NETWORK_LOGS); + pw.printf(" Makes all network logs available to the DPC and triggers " + + "DeviceAdminReceiver.onNetworkLogsAvailable() if needed.\n\n"); + pw.printf(" %s\n", CMD_FORCE_SECURITY_LOGS); + pw.printf(" Makes all security logs available to the DPC and triggers " + + "DeviceAdminReceiver.onSecurityLogsAvailable() if needed.\n\n"); + pw.printf(" %s [ %s <USER_ID> | current ] <COMPONENT>\n", + CMD_MARK_PO_ON_ORG_OWNED_DEVICE, USER_OPTION); + pw.printf(" Marks the profile owner of the given user as managing an organization-owned" + + "device. That will give it access to device identifiers (such as serial number, " + + "IMEI and MEID), as well as other privileges.\n\n"); } private int runIsSafeOperation(PrintWriter pw) { @@ -161,7 +227,6 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { return 0; } - private int runListPolicyExemptApps(PrintWriter pw) { List<String> apps = mService.listPolicyExemptApps(); int size = printAndGetSize(pw, apps, "policy exempt app"); @@ -174,4 +239,131 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { } return 0; } + + private int runSetActiveAdmin(PrintWriter pw) { + parseArgs(/* canHaveName= */ false); + mService.setActiveAdmin(mComponent, /* refreshing= */ true, mUserId); + + pw.printf("Success: Active admin set to component %s\n", mComponent.flattenToShortString()); + return 0; + } + + private int runSetDeviceOwner(PrintWriter pw) { + parseArgs(/* canHaveName= */ true); + mService.setActiveAdmin(mComponent, /* refreshing= */ true, mUserId); + + try { + if (!mService.setDeviceOwner(mComponent, mName, mUserId)) { + throw new RuntimeException( + "Can't set package " + mComponent + " as device owner."); + } + } catch (Exception e) { + // Need to remove the admin that we just added. + mService.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM); + throw e; + } + + mService.setUserProvisioningState( + DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId); + + pw.printf("Success: Device owner set to package %s\n", mComponent.flattenToShortString()); + pw.printf("Active admin set to component %s\n", mComponent.flattenToShortString()); + return 0; + } + + private int runRemoveActiveAdmin(PrintWriter pw) { + parseArgs(/* canHaveName= */ false); + mService.forceRemoveActiveAdmin(mComponent, mUserId); + pw.printf("Success: Admin removed %s\n", mComponent); + return 0; + } + + private int runSetProfileOwner(PrintWriter pw) { + parseArgs(/* canHaveName= */ true); + mService.setActiveAdmin(mComponent, /* refreshing= */ true, mUserId); + + try { + if (!mService.setProfileOwner(mComponent, mName, mUserId)) { + throw new RuntimeException("Can't set component " + + mComponent.flattenToShortString() + " as profile owner for user " + + mUserId); + } + } catch (Exception e) { + // Need to remove the admin that we just added. + mService.removeActiveAdmin(mComponent, mUserId); + throw e; + } + + mService.setUserProvisioningState( + DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId); + + pw.printf("Success: Active admin and profile owner set to %s for user %d\n", + mComponent.flattenToShortString(), mUserId); + return 0; + } + + private int runClearFreezePeriodRecord(PrintWriter pw) { + mService.clearSystemUpdatePolicyFreezePeriodRecord(); + pw.printf("Success\n"); + return 0; + } + + private int runForceNetworkLogs(PrintWriter pw) { + while (true) { + long toWait = mService.forceNetworkLogs(); + if (toWait == 0) { + break; + } + pw.printf("We have to wait for %d milliseconds...\n", toWait); + SystemClock.sleep(toWait); + } + pw.printf("Success\n"); + return 0; + } + + private int runForceSecurityLogs(PrintWriter pw) { + while (true) { + long toWait = mService.forceSecurityLogs(); + if (toWait == 0) { + break; + } + pw.printf("We have to wait for %d milliseconds...\n", toWait); + SystemClock.sleep(toWait); + } + pw.printf("Success\n"); + return 0; + } + + private int runMarkProfileOwnerOnOrganizationOwnedDevice(PrintWriter pw) { + parseArgs(/* canHaveName= */ false); + mService.markProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId); + pw.printf("Success\n"); + return 0; + } + + private void parseArgs(boolean canHaveName) { + String opt; + while ((opt = getNextOption()) != null) { + if (USER_OPTION.equals(opt)) { + String arg = getNextArgRequired(); + mUserId = UserHandle.parseUserArg(arg); + if (mUserId == UserHandle.USER_CURRENT) { + mUserId = ActivityManager.getCurrentUser(); + } + } else if (canHaveName && NAME_OPTION.equals(opt)) { + mName = getNextArgRequired(); + } else { + throw new IllegalArgumentException("Unknown option: " + opt); + } + } + mComponent = parseComponentName(getNextArgRequired()); + } + + private ComponentName parseComponentName(String component) { + ComponentName cn = ComponentName.unflattenFromString(component); + if (cn == null) { + throw new IllegalArgumentException("Invalid component " + component); + } + return cn; + } } diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index 4ce336d16f15..f3e7d672ec95 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -2394,26 +2394,20 @@ void IncrementalService::removeIfsStateCallbacks(StorageId storageId) { } void IncrementalService::getMetrics(StorageId storageId, android::os::PersistableBundle* result) { - const auto duration = getMillsSinceOldestPendingRead(storageId); - if (duration >= 0) { - const auto kMetricsMillisSinceOldestPendingRead = - os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_OLDEST_PENDING_READ(); - result->putLong(String16(kMetricsMillisSinceOldestPendingRead.data()), duration); - } -} - -long IncrementalService::getMillsSinceOldestPendingRead(StorageId storageId) { const auto ifs = getIfs(storageId); if (!ifs) { - LOG(ERROR) << "getMillsSinceOldestPendingRead failed, invalid storageId: " << storageId; - return -EINVAL; + LOG(ERROR) << "getMetrics failed, invalid storageId: " << storageId; + return; } + const auto kMetricsReadLogsEnabled = + os::incremental::BnIncrementalService::METRICS_READ_LOGS_ENABLED(); + result->putBoolean(String16(kMetricsReadLogsEnabled.data()), ifs->readLogsEnabled() != 0); + std::unique_lock l(ifs->lock); if (!ifs->dataLoaderStub) { - LOG(ERROR) << "getMillsSinceOldestPendingRead failed, no data loader: " << storageId; - return -EINVAL; + return; } - return ifs->dataLoaderStub->elapsedMsSinceOldestPendingRead(); + ifs->dataLoaderStub->getMetrics(result); } IncrementalService::DataLoaderStub::DataLoaderStub( @@ -2660,9 +2654,6 @@ bool IncrementalService::DataLoaderStub::fsmStep() { } switch (targetStatus) { - case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE: - // Do nothing, this is a reset state. - break; case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: { switch (currentStatus) { case IDataLoaderStatusListener::DATA_LOADER_BINDING: @@ -2683,8 +2674,12 @@ bool IncrementalService::DataLoaderStub::fsmStep() { } case IDataLoaderStatusListener::DATA_LOADER_CREATED: switch (currentStatus) { - case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE: + case IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE: + // Before binding need to make sure we are unbound. + // Otherwise we'll get stuck binding. + return destroy(); + case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: case IDataLoaderStatusListener::DATA_LOADER_BINDING: return bind(); case IDataLoaderStatusListener::DATA_LOADER_BOUND: @@ -2709,7 +2704,8 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount << ", but got: " << mountId; return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch."); } - if (newStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) { + if (newStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE || + newStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) { // User-provided status, let's postpone the handling to avoid possible deadlocks. mService.addTimedJob(*mService.mTimedQueue, id(), Constants::userStatusDelay, [this, newStatus]() { setCurrentStatus(newStatus); }); @@ -2721,7 +2717,7 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount } void IncrementalService::DataLoaderStub::setCurrentStatus(int newStatus) { - int targetStatus, oldStatus; + int oldStatus, oldTargetStatus, newTargetStatus; DataLoaderStatusListener listener; { std::unique_lock lock(mMutex); @@ -2730,22 +2726,31 @@ void IncrementalService::DataLoaderStub::setCurrentStatus(int newStatus) { } oldStatus = mCurrentStatus; - targetStatus = mTargetStatus; + oldTargetStatus = mTargetStatus; listener = mStatusListener; // Change the status. mCurrentStatus = newStatus; mCurrentStatusTs = mService.mClock->now(); - if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE || - mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) { - // For unavailable, unbind from DataLoader to ensure proper re-commit. - setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_DESTROYED); + switch (mCurrentStatus) { + case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE: + // Unavailable, retry. + setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_STARTED); + break; + case IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE: + // Unrecoverable, just unbind. + setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_DESTROYED); + break; + default: + break; } + + newTargetStatus = mTargetStatus; } LOG(DEBUG) << "Current status update for DataLoader " << id() << ": " << oldStatus << " -> " - << newStatus << " (target " << targetStatus << ")"; + << newStatus << " (target " << oldTargetStatus << " -> " << newTargetStatus << ")"; if (listener) { listener->onStatusChanged(id(), newStatus); @@ -2767,6 +2772,7 @@ void IncrementalService::DataLoaderStub::onHealthStatus(const StorageHealthListe if (healthListener) { healthListener->onHealthStatus(id(), healthStatus); } + mHealthStatus = healthStatus; } void IncrementalService::DataLoaderStub::updateHealthStatus(bool baseline) { @@ -2938,6 +2944,29 @@ BootClockTsUs IncrementalService::DataLoaderStub::getOldestTsFromLastPendingRead return result; } +void IncrementalService::DataLoaderStub::getMetrics(android::os::PersistableBundle* result) { + const auto duration = elapsedMsSinceOldestPendingRead(); + if (duration >= 0) { + const auto kMetricsMillisSinceOldestPendingRead = + os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_OLDEST_PENDING_READ(); + result->putLong(String16(kMetricsMillisSinceOldestPendingRead.data()), duration); + } + const auto kMetricsStorageHealthStatusCode = + os::incremental::BnIncrementalService::METRICS_STORAGE_HEALTH_STATUS_CODE(); + result->putInt(String16(kMetricsStorageHealthStatusCode.data()), mHealthStatus); + const auto kMetricsDataLoaderStatusCode = + os::incremental::BnIncrementalService::METRICS_DATA_LOADER_STATUS_CODE(); + result->putInt(String16(kMetricsDataLoaderStatusCode.data()), mCurrentStatus); + const auto kMetricsMillisSinceLastDataLoaderBind = + os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_LAST_DATA_LOADER_BIND(); + result->putLong(String16(kMetricsMillisSinceLastDataLoaderBind.data()), + (long)(elapsedMcs(mPreviousBindTs, mService.mClock->now()) / 1000)); + const auto kMetricsDataLoaderBindDelayMillis = + os::incremental::BnIncrementalService::METRICS_DATA_LOADER_BIND_DELAY_MILLIS(); + result->putLong(String16(kMetricsDataLoaderBindDelayMillis.data()), + (long)(mPreviousBindDelay.count())); +} + long IncrementalService::DataLoaderStub::elapsedMsSinceOldestPendingRead() { const auto oldestPendingReadKernelTs = getOldestTsFromLastPendingReads(); if (oldestPendingReadKernelTs == kMaxBootClockTsUs) { @@ -3007,7 +3036,7 @@ void IncrementalService::DataLoaderStub::onDump(int fd) { dprintf(fd, " bootClockTsUs: %lld\n", (long long)pendingRead.bootClockTsUs); } dprintf(fd, " bind: %llds ago (delay: %llds)\n", - (long long)(elapsedMcs(mPreviousBindTs, Clock::now()) / 1000000), + (long long)(elapsedMcs(mPreviousBindTs, mService.mClock->now()) / 1000000), (long long)(mPreviousBindDelay.count() / 1000)); dprintf(fd, " }\n"); const auto& params = mParams; diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index 95a17d1103e1..8dc789f4a328 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -249,7 +249,7 @@ private: bool isSystemDataLoader() const; void setHealthListener(const StorageHealthCheckParams& healthCheckParams, StorageHealthListener&& healthListener); - long elapsedMsSinceOldestPendingRead(); + void getMetrics(android::os::PersistableBundle* _aidl_return); private: binder::Status onStatusChanged(MountId mount, int newStatus) final; @@ -281,6 +281,7 @@ private: BootClockTsUs getOldestPendingReadTs(); BootClockTsUs getOldestTsFromLastPendingReads(); Milliseconds elapsedMsSinceKernelTs(TimePoint now, BootClockTsUs kernelTsUs); + long elapsedMsSinceOldestPendingRead(); // If the stub has to bind to the DL. // Returns {} if bind operation is already in progress. @@ -298,6 +299,7 @@ private: content::pm::FileSystemControlParcel mControl; DataLoaderStatusListener mStatusListener; StorageHealthListener mHealthListener; + std::atomic<int> mHealthStatus = IStorageHealthListener::HEALTH_STATUS_OK; std::condition_variable mStatusCondition; int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; @@ -468,7 +470,6 @@ private: bool updateLoadingProgress(int32_t storageId, StorageLoadingProgressListener&& progressListener); - long getMillsSinceOldestPendingRead(StorageId storage); void trimReservedSpaceV1(const IncFsMount& ifs); diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp index 6a3d953f74aa..68586a89ff07 100644 --- a/services/incremental/test/IncrementalServiceTest.cpp +++ b/services/incremental/test/IncrementalServiceTest.cpp @@ -126,7 +126,7 @@ private: class MockDataLoader : public IDataLoader { public: MockDataLoader() { - ON_CALL(*this, create(_, _, _, _)).WillByDefault(Invoke(this, &MockDataLoader::createOk)); + initializeCreateOk(); ON_CALL(*this, start(_)).WillByDefault(Invoke(this, &MockDataLoader::startOk)); ON_CALL(*this, stop(_)).WillByDefault(Invoke(this, &MockDataLoader::stopOk)); ON_CALL(*this, destroy(_)).WillByDefault(Invoke(this, &MockDataLoader::destroyOk)); @@ -145,6 +145,10 @@ public: binder::Status(int32_t id, const std::vector<InstallationFileParcel>& addedFiles, const std::vector<std::string>& removedFiles)); + void initializeCreateOk() { + ON_CALL(*this, create(_, _, _, _)).WillByDefault(Invoke(this, &MockDataLoader::createOk)); + } + void initializeCreateOkNoStatus() { ON_CALL(*this, create(_, _, _, _)) .WillByDefault(Invoke(this, &MockDataLoader::createOkNoStatus)); @@ -275,6 +279,14 @@ public: } return binder::Status::ok(); } + binder::Status bindToDataLoaderOkWithNoDelay(int32_t mountId, + const DataLoaderParamsParcel& params, + int bindDelayMs, + const sp<IDataLoaderStatusListener>& listener, + bool* _aidl_return) { + CHECK(bindDelayMs == 0) << bindDelayMs; + return bindToDataLoaderOk(mountId, params, bindDelayMs, listener, _aidl_return); + } binder::Status bindToDataLoaderOkWith1sDelay(int32_t mountId, const DataLoaderParamsParcel& params, int bindDelayMs, @@ -338,14 +350,13 @@ public: mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE); } binder::Status unbindFromDataLoaderOk(int32_t id) { + mBindDelayMs = -1; if (mDataLoader) { if (auto status = mDataLoader->destroy(id); !status.isOk()) { return status; } mDataLoader = nullptr; - } - mBindDelayMs = -1; - if (mListener) { + } else if (mListener) { mListener->onStatusChanged(id, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); } return binder::Status::ok(); @@ -775,16 +786,53 @@ public: mDataLoaderManager->getDataLoaderSuccess(); } - void checkMillisSinceOldestPendingRead(int storageId, long expected) { + void checkHealthMetrics(int storageId, long expectedMillisSinceOldestPendingRead, + int expectedStorageHealthStatusCode) { android::os::PersistableBundle result{}; mIncrementalService->getMetrics(storageId, &result); - int64_t value = -1; + ASSERT_EQ(6, (int)result.size()); + int64_t millisSinceOldestPendingRead = -1; ASSERT_TRUE(result.getLong(String16(BnIncrementalService:: METRICS_MILLIS_SINCE_OLDEST_PENDING_READ() .c_str()), - &value)); - ASSERT_EQ(expected, value); - ASSERT_EQ(1, (int)result.size()); + &millisSinceOldestPendingRead)); + ASSERT_EQ(expectedMillisSinceOldestPendingRead, millisSinceOldestPendingRead); + int storageHealthStatusCode = -1; + ASSERT_TRUE( + result.getInt(String16(BnIncrementalService::METRICS_STORAGE_HEALTH_STATUS_CODE() + .c_str()), + &storageHealthStatusCode)); + ASSERT_EQ(expectedStorageHealthStatusCode, storageHealthStatusCode); + int dataLoaderStatusCode = -1; + ASSERT_TRUE(result.getInt(String16(BnIncrementalService::METRICS_DATA_LOADER_STATUS_CODE() + .c_str()), + &dataLoaderStatusCode)); + ASSERT_EQ(IDataLoaderStatusListener::DATA_LOADER_STARTED, dataLoaderStatusCode); + } + + void checkBindingMetrics(int storageId, int64_t expectedMillisSinceLastDataLoaderBind, + int64_t expectedDataLoaderBindDelayMillis) { + android::os::PersistableBundle result{}; + mIncrementalService->getMetrics(storageId, &result); + ASSERT_EQ(6, (int)result.size()); + int dataLoaderStatus = -1; + ASSERT_TRUE(result.getInt(String16(BnIncrementalService::METRICS_DATA_LOADER_STATUS_CODE() + .c_str()), + &dataLoaderStatus)); + ASSERT_EQ(IDataLoaderStatusListener::DATA_LOADER_STARTED, dataLoaderStatus); + int64_t millisSinceLastDataLoaderBind = -1; + ASSERT_TRUE(result.getLong(String16(BnIncrementalService:: + METRICS_MILLIS_SINCE_LAST_DATA_LOADER_BIND() + .c_str()), + &millisSinceLastDataLoaderBind)); + ASSERT_EQ(expectedMillisSinceLastDataLoaderBind, millisSinceLastDataLoaderBind); + int64_t dataLoaderBindDelayMillis = -1; + ASSERT_TRUE( + result.getLong(String16( + BnIncrementalService::METRICS_DATA_LOADER_BIND_DELAY_MILLIS() + .c_str()), + &dataLoaderBindDelayMillis)); + ASSERT_EQ(expectedDataLoaderBindDelayMillis, dataLoaderBindDelayMillis); } protected: @@ -904,38 +952,55 @@ TEST_F(IncrementalServiceTest, testDataLoaderDestroyedAndDelayed) { ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) .WillByDefault(Invoke(mDataLoaderManager, &MockDataLoaderManager::bindToDataLoaderOkWith1sDelay)); + checkBindingMetrics(storageId, 0, 0); mClock->advanceMs(mDataLoaderManager->bindDelayMs()); + checkBindingMetrics(storageId, 0, 0); mDataLoaderManager->setDataLoaderStatusDestroyed(); ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) .WillByDefault(Invoke(mDataLoaderManager, &MockDataLoaderManager::bindToDataLoaderOkWith10sDelay)); + checkBindingMetrics(storageId, 0, mDataLoaderManager->bindDelayMs()); mClock->advanceMs(mDataLoaderManager->bindDelayMs()); + checkBindingMetrics(storageId, mDataLoaderManager->bindDelayMs(), + mDataLoaderManager->bindDelayMs()); mDataLoaderManager->setDataLoaderStatusDestroyed(); ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) .WillByDefault(Invoke(mDataLoaderManager, &MockDataLoaderManager::bindToDataLoaderOkWith100sDelay)); + checkBindingMetrics(storageId, 0, mDataLoaderManager->bindDelayMs()); mClock->advanceMs(mDataLoaderManager->bindDelayMs()); + checkBindingMetrics(storageId, mDataLoaderManager->bindDelayMs(), + mDataLoaderManager->bindDelayMs()); mDataLoaderManager->setDataLoaderStatusDestroyed(); ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) .WillByDefault(Invoke(mDataLoaderManager, &MockDataLoaderManager::bindToDataLoaderOkWith1000sDelay)); + checkBindingMetrics(storageId, 0, mDataLoaderManager->bindDelayMs()); mClock->advanceMs(mDataLoaderManager->bindDelayMs()); + checkBindingMetrics(storageId, mDataLoaderManager->bindDelayMs(), + mDataLoaderManager->bindDelayMs()); mDataLoaderManager->setDataLoaderStatusDestroyed(); ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) .WillByDefault(Invoke(mDataLoaderManager, &MockDataLoaderManager::bindToDataLoaderOkWith10000sDelay)); + checkBindingMetrics(storageId, 0, mDataLoaderManager->bindDelayMs()); // Try the reduced delay, just in case. mClock->advanceMs(mDataLoaderManager->bindDelayMs() / 2); + checkBindingMetrics(storageId, mDataLoaderManager->bindDelayMs() / 2, + mDataLoaderManager->bindDelayMs()); mDataLoaderManager->setDataLoaderStatusDestroyed(); ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) .WillByDefault(Invoke(mDataLoaderManager, &MockDataLoaderManager::bindToDataLoaderOkWith10000sDelay)); + checkBindingMetrics(storageId, 0, mDataLoaderManager->bindDelayMs()); mClock->advanceMs(mDataLoaderManager->bindDelayMs()); + checkBindingMetrics(storageId, mDataLoaderManager->bindDelayMs(), + mDataLoaderManager->bindDelayMs()); mDataLoaderManager->setDataLoaderStatusDestroyed(); } @@ -1156,12 +1221,81 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) { ASSERT_GE(storageId, 0); ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, {}, {})); - mDataLoaderManager->setDataLoaderStatusUnavailable(); + mDataLoaderManager->setDataLoaderStatusUnrecoverable(); + + // Timed callback present. + ASSERT_EQ(storageId, mTimedQueue->mId); + ASSERT_GE(mTimedQueue->mAfter, 10ms); + auto timedCallback = mTimedQueue->mWhat; + mTimedQueue->clearJob(storageId); + + // First callback call to propagate unrecoverable. + timedCallback(); + + // And second call to trigger recreation. ASSERT_NE(nullptr, mLooper->mCallback); ASSERT_NE(nullptr, mLooper->mCallbackData); mLooper->mCallback(-1, -1, mLooper->mCallbackData); } +TEST_F(IncrementalServiceTest, testStartDataLoaderUnavailable) { + mIncFs->openMountSuccess(); + mDataLoader->initializeCreateOkNoStatus(); + + EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)).Times(3); + EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(3); + EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(3); + EXPECT_CALL(*mDataLoader, start(_)).Times(1); + EXPECT_CALL(*mDataLoader, destroy(_)).Times(2); + EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); + EXPECT_CALL(*mLooper, addFd(MockIncFs::kPendingReadsFd, _, _, _, _)).Times(1); + EXPECT_CALL(*mLooper, removeFd(MockIncFs::kPendingReadsFd)).Times(1); + TemporaryDir tempDir; + int storageId = + mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel, + IncrementalService::CreateOptions::CreateNew); + ASSERT_GE(storageId, 0); + + ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(mDataLoaderManager, + &MockDataLoaderManager::bindToDataLoaderOkWithNoDelay)); + + ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, + {}, {})); + + // Unavailable. + mDataLoaderManager->setDataLoaderStatusUnavailable(); + + // Timed callback present. + ASSERT_EQ(storageId, mTimedQueue->mId); + ASSERT_GE(mTimedQueue->mAfter, 10ms); + auto timedCallback = mTimedQueue->mWhat; + mTimedQueue->clearJob(storageId); + + // Propagating unavailable and expecting it to trigger rebind with 1s retry delay. + ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(mDataLoaderManager, + &MockDataLoaderManager::bindToDataLoaderOkWith1sDelay)); + timedCallback(); + + // Unavailable #2. + mDataLoaderManager->setDataLoaderStatusUnavailable(); + + // Timed callback present. + ASSERT_EQ(storageId, mTimedQueue->mId); + ASSERT_GE(mTimedQueue->mAfter, 10ms); + timedCallback = mTimedQueue->mWhat; + mTimedQueue->clearJob(storageId); + + // Propagating unavailable and expecting it to trigger rebind with 10s retry delay. + // This time succeed. + mDataLoader->initializeCreateOk(); + ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(mDataLoaderManager, + &MockDataLoaderManager::bindToDataLoaderOkWith10sDelay)); + timedCallback(); +} + TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) { mIncFs->openMountSuccess(); @@ -1218,7 +1352,7 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) { ASSERT_NE(nullptr, mLooper->mCallbackData); ASSERT_EQ(storageId, listener->mStorageId); ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_OK, listener->mStatus); - checkMillisSinceOldestPendingRead(storageId, 0); + checkHealthMetrics(storageId, 0, listener->mStatus); // Looper/epoll callback. mIncFs->waitForPendingReadsSuccess(kFirstTimestampUs); @@ -1244,7 +1378,7 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) { ASSERT_EQ(nullptr, mLooper->mCallbackData); ASSERT_EQ(storageId, listener->mStorageId); ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_BLOCKED, listener->mStatus); - checkMillisSinceOldestPendingRead(storageId, params.blockedTimeoutMs); + checkHealthMetrics(storageId, params.blockedTimeoutMs, listener->mStatus); // Timed callback present. ASSERT_EQ(storageId, mTimedQueue->mId); @@ -1261,7 +1395,7 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) { ASSERT_EQ(nullptr, mLooper->mCallbackData); ASSERT_EQ(storageId, listener->mStorageId); ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_UNHEALTHY, listener->mStatus); - checkMillisSinceOldestPendingRead(storageId, params.unhealthyTimeoutMs); + checkHealthMetrics(storageId, params.unhealthyTimeoutMs, listener->mStatus); // Timed callback present. ASSERT_EQ(storageId, mTimedQueue->mId); @@ -1278,7 +1412,7 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) { ASSERT_EQ(nullptr, mLooper->mCallbackData); ASSERT_EQ(storageId, listener->mStorageId); ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_UNHEALTHY, listener->mStatus); - checkMillisSinceOldestPendingRead(storageId, params.unhealthyTimeoutMs); + checkHealthMetrics(storageId, params.unhealthyTimeoutMs, listener->mStatus); // Timed callback present. ASSERT_EQ(storageId, mTimedQueue->mId); @@ -1295,7 +1429,7 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) { ASSERT_NE(nullptr, mLooper->mCallbackData); ASSERT_EQ(storageId, listener->mStorageId); ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_OK, listener->mStatus); - checkMillisSinceOldestPendingRead(storageId, 0); + checkHealthMetrics(storageId, 0, listener->mStatus); } TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) { @@ -2025,7 +2159,7 @@ TEST_F(IncrementalServiceTest, testInvalidMetricsQuery) { ASSERT_TRUE(result.empty()); } -TEST_F(IncrementalServiceTest, testNoMetrics) { +TEST_F(IncrementalServiceTest, testNoDataLoaderMetrics) { mVold->setIncFsMountOptionsSuccess(); TemporaryDir tempDir; int storageId = @@ -2040,7 +2174,12 @@ TEST_F(IncrementalServiceTest, testNoMetrics) { .c_str()), &value)); ASSERT_EQ(expected, value); - ASSERT_EQ(0, (int)result.size()); + ASSERT_EQ(1, (int)result.size()); + bool expectedReadLogsEnabled = false; + ASSERT_TRUE( + result.getBoolean(String16(BnIncrementalService::METRICS_READ_LOGS_ENABLED().c_str()), + &expectedReadLogsEnabled)); + ASSERT_EQ(mVold->readLogsEnabled(), expectedReadLogsEnabled); } TEST_F(IncrementalServiceTest, testInvalidMetricsKeys) { @@ -2057,7 +2196,7 @@ TEST_F(IncrementalServiceTest, testInvalidMetricsKeys) { int64_t expected = -1, value = -1; ASSERT_FALSE(result.getLong(String16("invalid"), &value)); ASSERT_EQ(expected, value); - ASSERT_EQ(1, (int)result.size()); + ASSERT_EQ(6, (int)result.size()); } } // namespace android::os::incremental diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 6dedca190e2b..8dc501119af1 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -108,7 +108,6 @@ import com.android.server.attention.AttentionManagerService; import com.android.server.audio.AudioService; import com.android.server.biometrics.AuthService; import com.android.server.biometrics.BiometricService; -import com.android.server.biometrics.sensors.BiometricServiceCallback; import com.android.server.biometrics.sensors.face.FaceService; import com.android.server.biometrics.sensors.fingerprint.FingerprintService; import com.android.server.biometrics.sensors.iris.IrisService; @@ -214,11 +213,9 @@ import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.LinkedList; -import java.util.List; import java.util.Locale; import java.util.Timer; import java.util.TreeSet; @@ -2334,12 +2331,10 @@ public final class SystemServer implements Dumpable { final boolean hasFeatureFingerprint = mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT); - final List<BiometricServiceCallback> biometricServiceCallback = new ArrayList<>(); if (hasFeatureFace) { t.traceBegin("StartFaceSensor"); final FaceService faceService = mSystemServiceManager.startService(FaceService.class); - biometricServiceCallback.add(faceService); t.traceEnd(); } @@ -2353,18 +2348,12 @@ public final class SystemServer implements Dumpable { t.traceBegin("StartFingerprintSensor"); final FingerprintService fingerprintService = mSystemServiceManager.startService(FingerprintService.class); - biometricServiceCallback.add(fingerprintService); t.traceEnd(); } // Start this service after all biometric sensor services are started. t.traceBegin("StartBiometricService"); mSystemServiceManager.startService(BiometricService.class); - for (BiometricServiceCallback service : biometricServiceCallback) { - Slog.d(TAG, "Notifying onBiometricServiceReady for: " - + service.getClass().getSimpleName()); - service.onBiometricServiceReady(); - } t.traceEnd(); t.traceBegin("StartAuthService"); diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index 1208eccc69eb..9706d7f5f78d 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -23,11 +23,13 @@ import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ResolveInfo; import android.os.Handler; import android.os.IBinder.DeathRecipient; import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.os.UpdateEngine; import android.os.UpdateEngineCallback; import android.os.UserHandle; @@ -42,6 +44,9 @@ import com.android.server.wm.ActivityMetricsLaunchObserver; import com.android.server.wm.ActivityMetricsLaunchObserverRegistry; import com.android.server.wm.ActivityTaskManagerInternal; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; @@ -75,7 +80,7 @@ public final class ProfcollectForwardingService extends SystemService { */ public static boolean enabled() { return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, "enabled", - false); + false) || SystemProperties.getBoolean("persist.profcollectd.enabled_override", false); } @Override @@ -297,24 +302,20 @@ public final class ProfcollectForwardingService extends SystemService { return; } - final boolean uploadReport = - DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, - "upload_report", false); - new Thread(() -> { try { String reportUuid = mIProfcollect.report(); - if (!uploadReport) { + final int profileId = getBBProfileId(); + String reportDir = "/data/user/" + profileId + + "/com.google.android.apps.internal.betterbug/cache/"; + String reportPath = reportDir + reportUuid + ".zip"; + + if (!Files.exists(Paths.get(reportDir))) { + Log.i(LOG_TAG, "Destination directory does not exist, abort upload."); return; } - final int profileId = getBBProfileId(); - mIProfcollect.copy_report_to_bb(profileId, reportUuid); - String reportPath = - "/data/user/" + profileId - + "/com.google.android.apps.internal.betterbug/cache/" - + reportUuid + ".zip"; Intent uploadIntent = new Intent("com.google.android.apps.betterbug.intent.action.UPLOAD_PROFILE") .setPackage("com.google.android.apps.internal.betterbug") @@ -323,9 +324,15 @@ public final class ProfcollectForwardingService extends SystemService { .putExtra("EXTRA_PROFILE_PATH", reportPath) .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); Context context = getContext(); - if (context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0) != null) { - context.sendBroadcast(uploadIntent); + + List<ResolveInfo> receivers = + context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0); + if (receivers == null || receivers.isEmpty()) { + Log.i(LOG_TAG, "No one to receive upload intent, abort upload."); + return; } + mIProfcollect.copy_report_to_bb(profileId, reportUuid); + context.sendBroadcast(uploadIntent); mIProfcollect.delete_report(reportUuid); } catch (RemoteException e) { Log.e(LOG_TAG, e.getMessage()); diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index 683fbd17b78d..64dad7f0feab 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -51,6 +51,10 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSess import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; +import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_ALLOW_LIST; +import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_COMPAT; +import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE; +import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION; import static com.android.server.alarm.AlarmManagerService.ACTIVE_INDEX; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING_STATUS_CHANGED; @@ -76,6 +80,7 @@ import static com.android.server.alarm.AlarmManagerService.Constants.MAX_EXACT_A import static com.android.server.alarm.AlarmManagerService.FREQUENT_INDEX; import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY; import static com.android.server.alarm.AlarmManagerService.IS_WAKEUP_MASK; +import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_UNDEFINED; import static com.android.server.alarm.AlarmManagerService.TIME_CHANGED_MASK; import static com.android.server.alarm.AlarmManagerService.WORKING_INDEX; import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE; @@ -359,6 +364,7 @@ public class AlarmManagerServiceTest { .spyStatic(DeviceConfig.class) .mockStatic(LocalServices.class) .spyStatic(Looper.class) + .mockStatic(MetricsHelper.class) .mockStatic(Settings.Global.class) .mockStatic(ServiceManager.class) .spyStatic(UserHandle.class) @@ -418,6 +424,9 @@ public class AlarmManagerServiceTest { spyOn(mService); mService.onStart(); + // Unable to mock mMockContext to return a mock stats manager. + // So just mocking the whole MetricsHelper instance. + mService.mMetricsHelper = mock(MetricsHelper.class); spyOn(mService.mHandler); // Stubbing the handler. Test should simulate any handling of messages synchronously. doReturn(true).when(mService.mHandler).sendMessageAtTime(any(Message.class), anyLong()); @@ -492,7 +501,7 @@ public class AlarmManagerServiceTest { IAlarmListener listener) { mService.setImpl(type, triggerTime, windowLength, 0, null, listener, "test", FLAG_STANDALONE | FLAG_PRIORITIZE, null, null, TEST_CALLING_UID, - TEST_CALLING_PACKAGE, null); + TEST_CALLING_PACKAGE, null, 0); } private void setAllowWhileIdleAlarm(int type, long triggerTime, PendingIntent pi, @@ -516,12 +525,12 @@ public class AlarmManagerServiceTest { PendingIntent operation, long interval, int flags, int callingUid, String callingPackage, Bundle idleOptions) { mService.setImpl(type, triggerTime, windowLength, interval, operation, null, "test", flags, - null, null, callingUid, callingPackage, idleOptions); + null, null, callingUid, callingPackage, idleOptions, 0); } private void setTestAlarmWithListener(int type, long triggerTime, IAlarmListener listener) { mService.setImpl(type, triggerTime, WINDOW_EXACT, 0, null, listener, "test", - FLAG_STANDALONE, null, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null); + FLAG_STANDALONE, null, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null, 0); } @@ -763,10 +772,10 @@ public class AlarmManagerServiceTest { setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, pi6); assertEquals(mNowElapsedTest + 6, mTestTimer.getElapsed()); - mService.removeLocked(pi6, null); + mService.removeLocked(pi6, null, REMOVE_REASON_UNDEFINED); assertEquals(mNowElapsedTest + 8, mTestTimer.getElapsed()); - mService.removeLocked(pi8, null); + mService.removeLocked(pi8, null, REMOVE_REASON_UNDEFINED); assertEquals(mNowElapsedTest + 9, mTestTimer.getElapsed()); } @@ -1244,7 +1253,8 @@ public class AlarmManagerServiceTest { setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent()); } assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); - mService.removeLocked(TEST_CALLING_UID); + mService.removeLocked(TEST_CALLING_UID, + REMOVE_REASON_UNDEFINED); assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); } @@ -1284,7 +1294,7 @@ public class AlarmManagerServiceTest { } assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); for (int i = 0; i < numAlarms; i++) { - mService.removeLocked(pis[i], null); + mService.removeLocked(pis[i], null, REMOVE_REASON_UNDEFINED); assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); } } @@ -1414,7 +1424,7 @@ public class AlarmManagerServiceTest { mTestTimer.expire(); assertEquals(numAlarms, mService.mPendingNonWakeupAlarms.size()); for (int i = 0; i < numAlarms; i++) { - mService.removeLocked(pis[i], null); + mService.removeLocked(pis[i], null, REMOVE_REASON_UNDEFINED); assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); } } @@ -1484,13 +1494,13 @@ public class AlarmManagerServiceTest { assertEquals(trigger6, mTestTimer.getElapsed()); assertEquals(trigger6, mService.mNextWakeFromIdle.getWhenElapsed()); - mService.removeLocked(wakeFromIdle6, null); + mService.removeLocked(wakeFromIdle6, null, REMOVE_REASON_UNDEFINED); assertTrue(mService.mNextWakeFromIdle.matches(wakeFromIdle10, null)); assertEquals(trigger10, mTestTimer.getElapsed()); assertEquals(trigger10, mService.mNextWakeFromIdle.getWhenElapsed()); - mService.removeLocked(wakeFromIdle10, null); + mService.removeLocked(wakeFromIdle10, null, REMOVE_REASON_UNDEFINED); assertNull(mService.mNextWakeFromIdle); } @@ -1516,13 +1526,13 @@ public class AlarmManagerServiceTest { setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 12, wakeFromIdle12); assertEquals(mNowElapsedTest + 5, mService.mPendingIdleUntil.getWhenElapsed()); - mService.removeLocked(wakeFromIdle5, null); + mService.removeLocked(wakeFromIdle5, null, REMOVE_REASON_UNDEFINED); assertEquals(mNowElapsedTest + 8, mService.mPendingIdleUntil.getWhenElapsed()); - mService.removeLocked(wakeFromIdle8, null); + mService.removeLocked(wakeFromIdle8, null, REMOVE_REASON_UNDEFINED); assertEquals(requestedIdleUntil, mService.mPendingIdleUntil.getWhenElapsed()); - mService.removeLocked(idleUntilPi, null); + mService.removeLocked(idleUntilPi, null, REMOVE_REASON_UNDEFINED); assertNull(mService.mPendingIdleUntil); setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 15, idleUntilPi); @@ -1633,7 +1643,7 @@ public class AlarmManagerServiceTest { verify(pis[0], never()).send(eq(mMockContext), eq(0), any(Intent.class), any(), any(Handler.class), isNull(), any()); - mService.removeLocked(idleUntil, null); + mService.removeLocked(idleUntil, null, REMOVE_REASON_UNDEFINED); mTestTimer.expire(); // Now, the first 5 alarms (upto i = 4) should expire. for (int i = 0; i < 5; i++) { @@ -1680,14 +1690,16 @@ public class AlarmManagerServiceTest { getNewMockPendingIntent(), false), quota, mAllowWhileIdleWindow); // Refresh the state - mService.removeLocked(TEST_CALLING_UID); + mService.removeLocked(TEST_CALLING_UID, + REMOVE_REASON_UNDEFINED); mService.mAllowWhileIdleHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER); testQuotasDeferralOnExpiration(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger, getNewMockPendingIntent(), false), quota, mAllowWhileIdleWindow); // Refresh the state - mService.removeLocked(TEST_CALLING_UID); + mService.removeLocked(TEST_CALLING_UID, + REMOVE_REASON_UNDEFINED); mService.mAllowWhileIdleHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER); testQuotasNoDeferral(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger, @@ -1898,7 +1910,8 @@ public class AlarmManagerServiceTest { verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L), eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE), isNull(), isNull(), - eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull()); + eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(), + eq(EXACT_ALLOW_REASON_COMPAT)); } @Test @@ -1915,7 +1928,8 @@ public class AlarmManagerServiceTest { verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L), eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(), - eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture()); + eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(), + eq(EXACT_ALLOW_REASON_COMPAT)); final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue()); final int type = idleOptions.getTemporaryAppAllowlistType(); @@ -1935,7 +1949,8 @@ public class AlarmManagerServiceTest { final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), anyLong(), eq(0L), eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(), - isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture()); + isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(), + eq(EXACT_ALLOW_REASON_NOT_APPLICABLE)); final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue()); final int type = idleOptions.getTemporaryAppAllowlistType(); @@ -1955,7 +1970,8 @@ public class AlarmManagerServiceTest { verify(mService).setImpl(eq(RTC_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L), eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE | FLAG_WAKE_FROM_IDLE), - isNull(), eq(alarmClock), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull()); + isNull(), eq(alarmClock), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(), + eq(EXACT_ALLOW_REASON_COMPAT)); } @Test @@ -1979,7 +1995,7 @@ public class AlarmManagerServiceTest { verify(mService).setImpl(eq(RTC_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L), eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE | FLAG_WAKE_FROM_IDLE), isNull(), eq(alarmClock), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), - bundleCaptor.capture()); + bundleCaptor.capture(), eq(EXACT_ALLOW_REASON_PERMISSION)); final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue()); final int type = idleOptions.getTemporaryAppAllowlistType(); @@ -2042,7 +2058,8 @@ public class AlarmManagerServiceTest { verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L), eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE), isNull(), isNull(), - eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture()); + eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(), + eq(EXACT_ALLOW_REASON_PERMISSION)); final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue()); final int type = idleOptions.getTemporaryAppAllowlistType(); @@ -2067,7 +2084,8 @@ public class AlarmManagerServiceTest { verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L), eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE), isNull(), isNull(), - eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull()); + eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(), + eq(EXACT_ALLOW_REASON_ALLOW_LIST)); } @Test @@ -2087,7 +2105,8 @@ public class AlarmManagerServiceTest { verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L), eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE | FLAG_STANDALONE), isNull(), isNull(), - eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture()); + eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(), + eq(EXACT_ALLOW_REASON_PERMISSION)); final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue()); final int type = idleOptions.getTemporaryAppAllowlistType(); @@ -2113,7 +2132,8 @@ public class AlarmManagerServiceTest { verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L), eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(), - eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture()); + eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(), + eq(EXACT_ALLOW_REASON_ALLOW_LIST)); final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue()); final int type = idleOptions.getTemporaryAppAllowlistType(); @@ -2167,7 +2187,8 @@ public class AlarmManagerServiceTest { final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(4321L), anyLong(), eq(0L), eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(), - isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture()); + isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(), + eq(EXACT_ALLOW_REASON_NOT_APPLICABLE)); final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue()); final int type = idleOptions.getTemporaryAppAllowlistType(); @@ -2192,7 +2213,8 @@ public class AlarmManagerServiceTest { verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L), eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_STANDALONE), isNull(), isNull(), - eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull()); + eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(), + eq(EXACT_ALLOW_REASON_ALLOW_LIST)); } @Test @@ -2492,6 +2514,28 @@ public class AlarmManagerServiceTest { assertEquals(new ArraySet<>(appIds), mService.mExactAlarmCandidates); } + @Test + public void alarmScheduledAtomPushed() { + for (int i = 0; i < 10; i++) { + final PendingIntent pi = getNewMockPendingIntent(); + setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i, pi); + + verify(() -> MetricsHelper.pushAlarmScheduled(argThat(a -> a.matches(pi, null)))); + } + } + + @Test + public void alarmBatchDeliveredAtomPushed() throws InterruptedException { + for (int i = 0; i < 10; i++) { + final int type = ((i & 1) == 0) ? ELAPSED_REALTIME : ELAPSED_REALTIME_WAKEUP; + setTestAlarm(type, mNowElapsedTest + i, getNewMockPendingIntent()); + } + mNowElapsedTest += 100; + mTestTimer.expire(); + + verify(() -> MetricsHelper.pushAlarmBatchDelivered(10, 5)); + } + @After public void tearDown() { if (mMockingSession != null) { diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java index 12894ae4f75e..ba0e555020ac 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java @@ -18,7 +18,10 @@ package com.android.server.alarm; import static android.app.AlarmManager.ELAPSED_REALTIME; import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP; +import static android.app.AlarmManager.RTC; +import static android.app.AlarmManager.RTC_WAKEUP; +import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE; import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE; import static com.android.server.alarm.Constants.TEST_CALLING_UID; @@ -33,6 +36,7 @@ import android.app.AlarmManager; import android.app.PendingIntent; import android.platform.test.annotations.Presubmit; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -69,12 +73,13 @@ public class AlarmStoreTest { mock(PendingIntent.class)); return new Alarm(ELAPSED_REALTIME_WAKEUP, whenElapsed, whenElapsed, 0, 0, mock(PendingIntent.class), null, null, null, 0, info, TEST_CALLING_UID, - TEST_CALLING_PACKAGE, null); + TEST_CALLING_PACKAGE, null, EXACT_ALLOW_REASON_NOT_APPLICABLE); } private static Alarm createAlarm(int type, long whenElapsed, long windowLength, int flags) { return new Alarm(type, whenElapsed, whenElapsed, windowLength, 0, mock(PendingIntent.class), - null, null, null, flags, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null); + null, null, null, flags, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null, + EXACT_ALLOW_REASON_NOT_APPLICABLE); } private void addAlarmsToStore(Alarm... alarms) { @@ -83,6 +88,11 @@ public class AlarmStoreTest { } } + @Before + public void clear() { + mAlarmStore.remove(unused -> true); + } + @Test public void add() { final Alarm a1 = createAlarm(1, 0); @@ -209,7 +219,6 @@ public class AlarmStoreTest { final Alarm a8 = createAlarm(8, 0); final Alarm a10 = createAlarm(10, 0); addAlarmsToStore(a8, a10, a5); - assertEquals(5, mAlarmStore.getNextDeliveryTime()); mAlarmStore.updateAlarmDeliveries(a -> { @@ -241,4 +250,22 @@ public class AlarmStoreTest { mAlarmStore.remove(alarmClock::equals); verify(onRemoved).run(); } + + @Test + public void getCount() { + for (int i = 0; i < 10; i++) { + mAlarmStore.add(createAlarm(ELAPSED_REALTIME, i, 4, 0)); + } + assertEquals(5, mAlarmStore.getCount(a -> a.getRequestedElapsed() < 5)); + assertEquals(10, mAlarmStore.getCount(a -> a.windowLength == 4)); + + addAlarmsToStore( + createAlarm(RTC_WAKEUP, 45, 0, 53), + createAlarm(ELAPSED_REALTIME_WAKEUP, 60, 0, 53) + ); + + assertEquals(2, mAlarmStore.getCount(a -> a.wakeup)); + assertEquals(2, mAlarmStore.getCount(a -> a.flags == 53)); + assertEquals(0, mAlarmStore.getCount(a -> a.type == RTC)); + } } diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java index b64528c2f4d4..f11cba0db7b9 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java @@ -55,14 +55,14 @@ public class AlarmTest { private Alarm createDefaultAlarm(long requestedElapsed, long windowLength, int flags) { return new Alarm(ELAPSED_REALTIME, 0, requestedElapsed, windowLength, 0, createAlarmSender(), null, null, null, flags, null, TEST_CALLING_UID, - TEST_CALLING_PACKAGE, null); + TEST_CALLING_PACKAGE, null, 0); } private Alarm createAlarmClock(long requestedRtc) { final AlarmManager.AlarmClockInfo info = mock(AlarmManager.AlarmClockInfo.class); return new Alarm(RTC_WAKEUP, requestedRtc, requestedRtc, 0, 0, createAlarmSender(), null, null, null, FLAG_WAKE_FROM_IDLE | FLAG_STANDALONE, info, TEST_CALLING_UID, - TEST_CALLING_PACKAGE, null); + TEST_CALLING_PACKAGE, null, 0); } private PendingIntent createAlarmSender() { diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java index 0e795a938d48..403b4cd7e57e 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java @@ -45,7 +45,7 @@ public class BackgroundRestrictedAlarmsTest { } uidAlarms.add(new Alarm( removeIt ? RTC : RTC_WAKEUP, - 0, 0, 0, 0, null, null, null, null, 0, null, uid, name, null)); + 0, 0, 0, 0, null, null, null, null, 0, null, uid, name, null, 0)); return all; } diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java index ed2e4669f9d3..a2e813aed720 100644 --- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java @@ -62,7 +62,6 @@ import com.android.server.pm.parsing.pkg.AndroidPackage; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.quality.Strictness; @@ -223,7 +222,6 @@ public class AppOpsServiceTest { // Tests that ops are persisted during shutdown. @Test - @Ignore("b/183523911") public void testShutdown() { mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java index 45f43e8b672f..ee00cb24a991 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java @@ -43,9 +43,12 @@ import android.appwidget.AppWidgetManagerInternal; import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; +import android.content.pm.InstallSourceInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.pm.SigningInfo; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; @@ -81,8 +84,10 @@ public class AccessibilitySecurityPolicyTest { private static final int APP_PID = 2000; private static final int SYSTEM_PID = 558; private static final int TEST_USER_ID = UserHandle.USER_SYSTEM; + private static final String TEST_PACKAGE_NAME = "com.android.server.accessibility"; private static final ComponentName TEST_COMPONENT_NAME = new ComponentName( - "com.android.server.accessibility", "AccessibilitySecurityPolicyTest"); + TEST_PACKAGE_NAME, "AccessibilitySecurityPolicyTest"); + private static final String ALLOWED_INSTALL_PACKAGE_NAME = "com.allowed.install.package"; private static final int[] ALWAYS_DISPATCH_EVENTS = { AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, @@ -142,19 +147,40 @@ public class AccessibilitySecurityPolicyTest { @Mock private AccessibilityServiceInfo mMockA11yServiceInfo; @Mock + private ResolveInfo mMockResolveInfo; + @Mock + private ServiceInfo mMockServiceInfo; + @Mock + private ApplicationInfo mMockApplicationInfo; + @Mock + private ApplicationInfo mMockSourceApplicationInfo; + @Mock + private PackageInfo mMockSourcePackageInfo; + @Mock private PolicyWarningUIController mPolicyWarningUIController; @Before - public void setUp() { + public void setUp() throws PackageManager.NameNotFoundException { MockitoAnnotations.initMocks(this); mContext.setMockPackageManager(mMockPackageManager); mContext.addMockSystemService(Context.USER_SERVICE, mMockUserManager); mContext.addMockSystemService(Context.APP_OPS_SERVICE, mMockAppOpsManager); mContext.getOrCreateTestableResources().addOverride( R.dimen.accessibility_focus_highlight_stroke_width, 1); + mContext.getOrCreateTestableResources().addOverride(R.array + .config_accessibility_allowed_install_source, + new String[]{ALLOWED_INSTALL_PACKAGE_NAME}); + when(mMockA11yServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo); when(mMockA11yServiceInfo.getComponentName()).thenReturn(TEST_COMPONENT_NAME); when(mMockA11yServiceConnection.getServiceInfo()).thenReturn(mMockA11yServiceInfo); + when(mMockPackageManager.getPackageInfo(ALLOWED_INSTALL_PACKAGE_NAME, 0)).thenReturn( + mMockSourcePackageInfo); + + mMockResolveInfo.serviceInfo = mMockServiceInfo; + mMockServiceInfo.applicationInfo = mMockApplicationInfo; + mMockServiceInfo.packageName = TEST_PACKAGE_NAME; + mMockSourcePackageInfo.applicationInfo = mMockSourceApplicationInfo; mA11ySecurityPolicy = new AccessibilitySecurityPolicy( mPolicyWarningUIController, mContext, mMockA11yUserManager); @@ -595,9 +621,32 @@ public class AccessibilitySecurityPolicyTest { } @Test - public void onBoundServicesChanged_bindA11yCategoryService_noUIControllerAction() { + public void onBoundServicesChanged_bindNonA11yToolService_activateUIControllerAction() { final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>(); boundServices.add(mMockA11yServiceConnection); + when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(false); + + mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices); + + verify(mPolicyWarningUIController).onNonA11yCategoryServiceBound(eq(TEST_USER_ID), + eq(TEST_COMPONENT_NAME)); + } + + @Test + public void onBoundServicesChanged_unbindNonA11yToolService_activateUIControllerAction() { + onBoundServicesChanged_bindNonA11yToolService_activateUIControllerAction(); + + mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>()); + + verify(mPolicyWarningUIController).onNonA11yCategoryServiceUnbound(eq(TEST_USER_ID), + eq(TEST_COMPONENT_NAME)); + } + + @Test + public void onBoundServicesChanged_bindSystemA11yToolService_noUIControllerAction() { + final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>(); + boundServices.add(mMockA11yServiceConnection); + when(mMockApplicationInfo.isSystemApp()).thenReturn(true); when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(true); mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices); @@ -606,8 +655,8 @@ public class AccessibilitySecurityPolicyTest { } @Test - public void onBoundServicesChanged_unbindA11yCategoryService_noUIControllerAction() { - onBoundServicesChanged_bindA11yCategoryService_noUIControllerAction(); + public void onBoundServicesChanged_unbindSystemA11yToolService_noUIControllerAction() { + onBoundServicesChanged_bindSystemA11yToolService_noUIControllerAction(); mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>()); @@ -616,30 +665,43 @@ public class AccessibilitySecurityPolicyTest { } @Test - public void onBoundServicesChanged_bindNonA11yCategoryService_activateUIControllerAction() { + public void onBoundServicesChanged_bindAllowedSourceA11yToolService_noUIControllerAction() + throws PackageManager.NameNotFoundException { final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>(); boundServices.add(mMockA11yServiceConnection); - when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(false); + when(mMockApplicationInfo.isSystemApp()).thenReturn(false); + final InstallSourceInfo installSourceInfo = new InstallSourceInfo( + ALLOWED_INSTALL_PACKAGE_NAME, new SigningInfo(), null, + ALLOWED_INSTALL_PACKAGE_NAME); + when(mMockPackageManager.getInstallSourceInfo(TEST_PACKAGE_NAME)).thenReturn( + installSourceInfo); + when(mMockSourceApplicationInfo.isSystemApp()).thenReturn(true); + when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(true); mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices); - verify(mPolicyWarningUIController).onNonA11yCategoryServiceBound(eq(TEST_USER_ID), - eq(TEST_COMPONENT_NAME)); + verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceBound(anyInt(), any()); } @Test - public void onBoundServicesChanged_unbindNonA11yCategoryService_activateUIControllerAction() { - onBoundServicesChanged_bindNonA11yCategoryService_activateUIControllerAction(); + public void onBoundServicesChanged_bindUnknownSourceA11yToolService_activateUIControllerAction() + throws PackageManager.NameNotFoundException { + final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>(); + boundServices.add(mMockA11yServiceConnection); + when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(true); + final InstallSourceInfo installSourceInfo = new InstallSourceInfo(null, null, null, null); + when(mMockPackageManager.getInstallSourceInfo(TEST_PACKAGE_NAME)).thenReturn( + installSourceInfo); - mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>()); + mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices); - verify(mPolicyWarningUIController).onNonA11yCategoryServiceUnbound(eq(TEST_USER_ID), + verify(mPolicyWarningUIController).onNonA11yCategoryServiceBound(eq(TEST_USER_ID), eq(TEST_COMPONENT_NAME)); } @Test public void onSwitchUser_differentUser_activateUIControllerAction() { - onBoundServicesChanged_bindNonA11yCategoryService_activateUIControllerAction(); + onBoundServicesChanged_bindNonA11yToolService_activateUIControllerAction(); mA11ySecurityPolicy.onSwitchUserLocked(2, new HashSet<>()); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerUtilsTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerUtilsTest.java new file mode 100644 index 000000000000..96103e36ae92 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerUtilsTest.java @@ -0,0 +1,130 @@ +/* + * 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.am; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.fail; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +@SmallTest +public class ActivityManagerUtilsTest { + @Test + public void getAndroidIdHash() { + // getAndroidIdHash() essentially returns a random a value. Just make sure it's + // non-negative. + assertThat(ActivityManagerUtils.getAndroidIdHash()).isAtLeast(0); + } + + @Test + public void getUnsignedHashCached() { + assertThat(ActivityManagerUtils.getUnsignedHashCached("x")).isEqualTo( + ActivityManagerUtils.getUnsignedHashCached("x")); + + assertThat(ActivityManagerUtils.getUnsignedHashCached("x")).isNotEqualTo( + ActivityManagerUtils.getUnsignedHashCached("y")); + } + + @Test + public void shouldSamplePackage_sampleNone() { + final int numTests = 100000; + for (int i = 0; i < numTests; i++) { + assertThat(ActivityManagerUtils.shouldSamplePackageForAtom("" + i, 0)) + .isFalse(); + } + } + + @Test + public void shouldSamplePackage_sampleAll() { + final int numTests = 100000; + + for (int i = 0; i < numTests; i++) { + assertThat(ActivityManagerUtils.shouldSamplePackageForAtom("" + i, 1)) + .isTrue(); + } + } + + /** + * Make sure, with the same android ID, an expected rate of the packages are selected. + */ + @Test + public void shouldSamplePackage_sampleSome_fixedAndroidId() { + checkShouldSamplePackage_fixedAndroidId(0.1f); + checkShouldSamplePackage_fixedAndroidId(0.5f); + checkShouldSamplePackage_fixedAndroidId(0.9f); + } + + /** + * Make sure, the same package is selected on an expected rate of the devices. + */ + @Test + public void shouldSamplePackage_sampleSome_fixedPackage() { + checkShouldSamplePackage_fixedPackage(0.1f); + checkShouldSamplePackage_fixedPackage(0.5f); + checkShouldSamplePackage_fixedPackage(0.9f); + } + + private void checkShouldSamplePackage_fixedPackage(float sampleRate) { + checkShouldSamplePackage(sampleRate, sampleRate, true, false); + } + + private void checkShouldSamplePackage_fixedAndroidId(float sampleRate) { + checkShouldSamplePackage(sampleRate, sampleRate, false, true); + } + + @Test + public void testSheckShouldSamplePackage() { + // Just make sure checkShouldSamplePackage is actually working... + try { + checkShouldSamplePackage(0.3f, 0.6f, false, true); + fail(); + } catch (AssertionError expected) { + } + try { + checkShouldSamplePackage(0.6f, 0.3f, true, false); + fail(); + } catch (AssertionError expected) { + } + } + + private void checkShouldSamplePackage(float inputSampleRate, float expectedRate, + boolean fixedPackage, boolean fixedAndroidId) { + final int numTests = 100000; + + try { + int numSampled = 0; + for (int i = 0; i < numTests; i++) { + final String pkg = fixedPackage ? "fixed-package" : "" + i; + ActivityManagerUtils.injectAndroidIdForTest( + fixedAndroidId ? "fixed-android-id" : "" + i); + + if (ActivityManagerUtils.shouldSamplePackageForAtom(pkg, inputSampleRate)) { + numSampled++; + } + assertThat(ActivityManagerUtils.getUnsignedHashCached(pkg)).isEqualTo( + ActivityManagerUtils.getUnsignedHashCached(pkg)); + } + final double actualSampleRate = ((double) numSampled) / numTests; + + assertThat(actualSampleRate).isWithin(0.05).of(expectedRate); + } finally { + ActivityManagerUtils.injectAndroidIdForTest(null); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java index 4a6c9be58c11..5c7a580a2593 100644 --- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java @@ -16,6 +16,9 @@ package com.android.server.apphibernation; +import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED; +import static android.app.usage.UsageEvents.Event.APP_COMPONENT_USED; +import static android.app.usage.UsageEvents.Event.USER_INTERACTION; import static android.content.pm.PackageManager.MATCH_ANY_USER; import static org.junit.Assert.assertEquals; @@ -34,6 +37,9 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.IActivityManager; +import android.app.usage.UsageEvents.Event; +import android.app.usage.UsageStatsManagerInternal; +import android.app.usage.UsageStatsManagerInternal.UsageEventListener; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -81,6 +87,8 @@ public final class AppHibernationServiceTest { private AppHibernationService mAppHibernationService; private BroadcastReceiver mBroadcastReceiver; + private UsageEventListener mUsageEventListener; + @Mock private Context mContext; @Mock @@ -93,8 +101,14 @@ public final class AppHibernationServiceTest { private UserManager mUserManager; @Mock private HibernationStateDiskStore<UserLevelState> mUserLevelDiskStore; + @Mock + private UsageStatsManagerInternal mUsageStatsManagerInternal; + @Mock + private HibernationStateDiskStore<UserLevelState> mHibernationStateDiskStore; @Captor private ArgumentCaptor<BroadcastReceiver> mReceiverCaptor; + @Captor + private ArgumentCaptor<UsageEventListener> mUsageEventListenerCaptor; @Before public void setUp() throws RemoteException { @@ -108,6 +122,8 @@ public final class AppHibernationServiceTest { verify(mContext).registerReceiver(mReceiverCaptor.capture(), any()); mBroadcastReceiver = mReceiverCaptor.getValue(); + verify(mUsageStatsManagerInternal).registerListener(mUsageEventListenerCaptor.capture()); + mUsageEventListener = mUsageEventListenerCaptor.getValue(); doReturn(mUserInfos).when(mUserManager).getUsers(); @@ -284,6 +300,89 @@ public final class AppHibernationServiceTest { assertEquals(capturedIntents.get(1).getAction(), Intent.ACTION_BOOT_COMPLETED); } + @Test + public void testHibernatingPackageIsUnhibernatedForUserWhenUserInteracted() { + // GIVEN a package that is currently hibernated for a user + mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true); + + // WHEN the package is interacted with by user + generateUsageEvent(USER_INTERACTION); + + // THEN the package is not hibernating anymore + assertFalse(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1)); + } + + @Test + public void testHibernatingPackageIsUnhibernatedForUserWhenActivityResumed() { + // GIVEN a package that is currently hibernated for a user + mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true); + + // WHEN the package has activity resumed + generateUsageEvent(ACTIVITY_RESUMED); + + // THEN the package is not hibernating anymore + assertFalse(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1)); + } + + @Test + public void testHibernatingPackageIsUnhibernatedForUserWhenComponentUsed() { + // GIVEN a package that is currently hibernated for a user + mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true); + + // WHEN a package component is used + generateUsageEvent(APP_COMPONENT_USED); + + // THEN the package is not hibernating anymore + assertFalse(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1)); + } + + @Test + public void testHibernatingPackageIsUnhibernatedGloballyWhenUserInteracted() { + // GIVEN a package that is currently hibernated globally + mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true); + + // WHEN the user interacts with the package + generateUsageEvent(USER_INTERACTION); + + // THEN the package is not hibernating globally anymore + assertFalse(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1)); + } + + @Test + public void testHibernatingPackageIsUnhibernatedGloballyWhenActivityResumed() { + // GIVEN a package that is currently hibernated globally + mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true); + + // WHEN activity in package resumed + generateUsageEvent(ACTIVITY_RESUMED); + + // THEN the package is not hibernating globally anymore + assertFalse(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1)); + } + + @Test + public void testHibernatingPackageIsUnhibernatedGloballyWhenComponentUsed() { + // GIVEN a package that is currently hibernated globally + mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true); + + // WHEN a package component is used + generateUsageEvent(APP_COMPONENT_USED); + + // THEN the package is not hibernating globally anymore + assertFalse(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1)); + } + + /** + * Mock a usage event occurring. + * + * @param usageEventId id of a usage event + */ + private void generateUsageEvent(int usageEventId) { + Event event = new Event(usageEventId, 0 /* timestamp */); + event.mPackage = PACKAGE_NAME_1; + mUsageEventListener.onUsageEvent(USER_ID_1, event); + } + /** * Add a mock user with one package. */ @@ -360,6 +459,11 @@ public final class AppHibernationServiceTest { } @Override + public UsageStatsManagerInternal getUsageStatsManagerInternal() { + return mUsageStatsManagerInternal; + } + + @Override public Executor getBackgroundExecutor() { // Just execute immediately in tests. return r -> r.run(); diff --git a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java index b552fd5e8718..79e5865abd82 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java @@ -70,7 +70,8 @@ public class AppSearchImplPlatformTest { mTemporaryFolder.newFolder(), mContext, mContext.getUserId(), - mContext.getPackageName()); + mContext.getPackageName(), + /*logger=*/ null); mGlobalQuerierUid = mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0); } @@ -117,9 +118,8 @@ public class AppSearchImplPlatformTest { // No query filters specified, global query can retrieve all documents. SearchSpec searchSpec = new SearchSpec.Builder().setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY).build(); - SearchResultPage searchResultPage = - mAppSearchImpl.globalQuery( - "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid); + SearchResultPage searchResultPage = mAppSearchImpl.globalQuery( + "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid, /*logger=*/ null); assertThat(searchResultPage.getResults()).hasSize(2); // Document2 will be first since it got indexed later and has a "better", aka more recent @@ -174,9 +174,8 @@ public class AppSearchImplPlatformTest { .setTermMatch(SearchSpec.TERM_MATCH_PREFIX) .addFilterPackageNames("package1") .build(); - SearchResultPage searchResultPage = - mAppSearchImpl.globalQuery( - "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid); + SearchResultPage searchResultPage = mAppSearchImpl.globalQuery( + "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid, /*logger=*/ null); assertThat(searchResultPage.getResults()).hasSize(1); assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1); @@ -186,9 +185,8 @@ public class AppSearchImplPlatformTest { .setTermMatch(SearchSpec.TERM_MATCH_PREFIX) .addFilterPackageNames("package2") .build(); - searchResultPage = - mAppSearchImpl.globalQuery( - "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid); + searchResultPage = mAppSearchImpl.globalQuery( + "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid, /*logger=*/ null); assertThat(searchResultPage.getResults()).hasSize(1); assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2); } diff --git a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java b/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java index 11ae76b94495..28955d6e727f 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java @@ -67,7 +67,8 @@ public class VisibilityStoreTest { mTemporaryFolder.newFolder(), mContext, mContext.getUserId(), - /*globalQuerierPackage=*/ mContext.getPackageName()); + /*globalQuerierPackage=*/ mContext.getPackageName(), + /*logger=*/ null); mGlobalQuerierUid = mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0); @@ -163,7 +164,8 @@ public class VisibilityStoreTest { mTemporaryFolder.newFolder(), mContext, mContext.getUserId(), - /*globalQuerierPackage=*/ mContext.getPackageName()); + /*globalQuerierPackage=*/ mContext.getPackageName(), + /*logger=*/ null); VisibilityStore visibilityStore = appSearchImpl.getVisibilityStoreLocked(); // Use some arbitrary callerUid. If we can't find the global querier's uid though, diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java index 9a7cf803763d..b36720303a55 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java @@ -82,7 +82,8 @@ public class AppSearchImplTest { mTemporaryFolder.newFolder(), context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ context.getPackageName()); + /*globalQuerierPackage=*/ context.getPackageName(), + /*logger=*/ null); } // TODO(b/175430168) add test to verify reset is working properly. @@ -604,7 +605,7 @@ public class AppSearchImplTest { SearchSpec searchSpec = new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); SearchResultPage searchResultPage = - mAppSearchImpl.query("package", "EmptyDatabase", "", searchSpec); + mAppSearchImpl.query("package", "EmptyDatabase", "", searchSpec, /*logger=*/ null); assertThat(searchResultPage.getResults()).isEmpty(); } @@ -647,7 +648,7 @@ public class AppSearchImplTest { SearchSpec searchSpec = new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); SearchResultPage searchResultPage = - mAppSearchImpl.query("package2", "database2", "", searchSpec); + mAppSearchImpl.query("package2", "database2", "", searchSpec, /*logger=*/ null); assertThat(searchResultPage.getResults()).isEmpty(); // Insert package2 document @@ -655,7 +656,9 @@ public class AppSearchImplTest { mAppSearchImpl.putDocument("package2", "database2", document, /*logger=*/ null); // No query filters specified. package2 should only get its own documents back. - searchResultPage = mAppSearchImpl.query("package2", "database2", "", searchSpec); + searchResultPage = + mAppSearchImpl.query("package2", "database2", "", searchSpec, /*logger= + */ null); assertThat(searchResultPage.getResults()).hasSize(1); assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document); } @@ -703,7 +706,7 @@ public class AppSearchImplTest { .addFilterPackageNames("package1") .build(); SearchResultPage searchResultPage = - mAppSearchImpl.query("package2", "database2", "", searchSpec); + mAppSearchImpl.query("package2", "database2", "", searchSpec, /*logger=*/ null); assertThat(searchResultPage.getResults()).isEmpty(); // Insert package2 document @@ -716,7 +719,9 @@ public class AppSearchImplTest { .setTermMatch(TermMatchType.Code.PREFIX_VALUE) .addFilterPackageNames("package2") .build(); - searchResultPage = mAppSearchImpl.query("package2", "database2", "", searchSpec); + searchResultPage = + mAppSearchImpl.query("package2", "database2", "", searchSpec, /*logger= + */ null); assertThat(searchResultPage.getResults()).hasSize(1); assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document); } @@ -727,7 +732,11 @@ public class AppSearchImplTest { new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); SearchResultPage searchResultPage = mAppSearchImpl.globalQuery( - "", searchSpec, /*callerPackageName=*/ "", /*callerUid=*/ 0); + "", + searchSpec, + /*callerPackageName=*/ "", + /*callerUid=*/ 0, + /*logger=*/ null); assertThat(searchResultPage.getResults()).isEmpty(); } @@ -1033,7 +1042,12 @@ public class AppSearchImplTest { SearchSpec searchSpec = new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); SearchResultPage searchResultPage = - mAppSearchImpl.query("package", "database", /*queryExpression=*/ "", searchSpec); + mAppSearchImpl.query( + "package", + "database", + /*queryExpression=*/ "", + searchSpec, + /*logger=*/ null); assertThat(searchResultPage.getResults()).hasSize(1); assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document); @@ -1042,7 +1056,12 @@ public class AppSearchImplTest { // Verify the document is cleared. searchResultPage = - mAppSearchImpl.query("package2", "database2", /*queryExpression=*/ "", searchSpec); + mAppSearchImpl.query( + "package2", + "database2", + /*queryExpression=*/ "", + searchSpec, + /*logger=*/ null); assertThat(searchResultPage.getResults()).isEmpty(); // Verify the schema is cleared. @@ -1244,7 +1263,8 @@ public class AppSearchImplTest { new SearchSpec.Builder() .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY) .setRankingStrategy(SearchSpec.RANKING_STRATEGY_USAGE_COUNT) - .build()) + .build(), + /*logger=*/ null) .getResults(); assertThat(page).hasSize(2); assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id1"); @@ -1262,7 +1282,8 @@ public class AppSearchImplTest { .setRankingStrategy( SearchSpec .RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP) - .build()) + .build(), + /*logger=*/ null) .getResults(); assertThat(page).hasSize(2); assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id2"); @@ -1279,7 +1300,8 @@ public class AppSearchImplTest { .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY) .setRankingStrategy( SearchSpec.RANKING_STRATEGY_SYSTEM_USAGE_COUNT) - .build()) + .build(), + /*logger=*/ null) .getResults(); assertThat(page).hasSize(2); assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id2"); @@ -1297,7 +1319,8 @@ public class AppSearchImplTest { .setRankingStrategy( SearchSpec .RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP) - .build()) + .build(), + /*logger=*/ null) .getResults(); assertThat(page).hasSize(2); assertThat(page.get(0).getGenericDocument().getId()).isEqualTo("id1"); @@ -1499,7 +1522,9 @@ public class AppSearchImplTest { mTemporaryFolder.newFolder(), context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger + =*/ null); // Initial check that we could do something at first. List<AppSearchSchema> schemas = @@ -1561,7 +1586,8 @@ public class AppSearchImplTest { "query", new SearchSpec.Builder() .setTermMatch(TermMatchType.Code.PREFIX_VALUE) - .build()); + .build(), + /*logger=*/ null); }); expectThrows( @@ -1573,7 +1599,8 @@ public class AppSearchImplTest { .setTermMatch(TermMatchType.Code.PREFIX_VALUE) .build(), "package", - /*callerUid=*/ 1); + /*callerUid=*/ 1, + /*logger=*/ null); }); expectThrows( @@ -1647,7 +1674,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); List<AppSearchSchema> schemas = Collections.singletonList(new AppSearchSchema.Builder("type").build()); @@ -1677,7 +1705,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); getResult = appSearchImpl2.getDocument( "package", "database", "namespace1", "id1", Collections.emptyMap()); @@ -1694,7 +1723,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); List<AppSearchSchema> schemas = Collections.singletonList(new AppSearchSchema.Builder("type").build()); @@ -1748,7 +1778,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); expectThrows( AppSearchException.class, () -> @@ -1774,7 +1805,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); List<AppSearchSchema> schemas = Collections.singletonList(new AppSearchSchema.Builder("type").build()); @@ -1835,7 +1867,8 @@ public class AppSearchImplTest { appsearchDir, context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ ""); + /*globalQuerierPackage=*/ "", + /*logger=*/ null); expectThrows( AppSearchException.class, () -> diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java index 1194e76ee2b5..5989bb65bd39 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java @@ -23,13 +23,21 @@ import android.annotation.Nullable; import android.app.appsearch.AppSearchResult; import android.app.appsearch.AppSearchSchema; import android.app.appsearch.GenericDocument; +import android.app.appsearch.SearchResultPage; +import android.app.appsearch.SearchSpec; import android.content.Context; import androidx.test.core.app.ApplicationProvider; import com.android.server.appsearch.external.localstorage.stats.CallStats; +import com.android.server.appsearch.external.localstorage.stats.InitializeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; +import com.android.server.appsearch.external.localstorage.stats.SearchStats; +import com.android.server.appsearch.proto.InitializeStatsProto; import com.android.server.appsearch.proto.PutDocumentStatsProto; +import com.android.server.appsearch.proto.QueryStatsProto; +import com.android.server.appsearch.proto.ScoringSpecProto; +import com.android.server.appsearch.proto.TermMatchType; import org.junit.Before; import org.junit.Rule; @@ -54,23 +62,93 @@ public class AppSearchLoggerTest { mTemporaryFolder.newFolder(), context, VisibilityStore.NO_OP_USER_ID, - /*globalQuerierPackage=*/ context.getPackageName()); + /*globalQuerierPackage=*/ context.getPackageName(), + /*logger=*/ null); mLogger = new TestLogger(); } // Test only not thread safe. public class TestLogger implements AppSearchLogger { + @Nullable CallStats mCallStats; @Nullable PutDocumentStats mPutDocumentStats; + @Nullable InitializeStats mInitializeStats; + @Nullable SearchStats mSearchStats; @Override public void logStats(@NonNull CallStats stats) { - throw new UnsupportedOperationException(); + mCallStats = stats; } @Override public void logStats(@NonNull PutDocumentStats stats) { mPutDocumentStats = stats; } + + @Override + public void logStats(@NonNull InitializeStats stats) { + mInitializeStats = stats; + } + + @Override + public void logStats(@NonNull SearchStats stats) { + mSearchStats = stats; + } + } + + @Test + public void testAppSearchLoggerHelper_testCopyNativeStats_initialize() { + int nativeLatencyMillis = 3; + int nativeDocumentStoreRecoveryCause = InitializeStatsProto.RecoveryCause.DATA_LOSS_VALUE; + int nativeIndexRestorationCause = + InitializeStatsProto.RecoveryCause.INCONSISTENT_WITH_GROUND_TRUTH_VALUE; + int nativeSchemaStoreRecoveryCause = + InitializeStatsProto.RecoveryCause.TOTAL_CHECKSUM_MISMATCH_VALUE; + int nativeDocumentStoreRecoveryLatencyMillis = 7; + int nativeIndexRestorationLatencyMillis = 8; + int nativeSchemaStoreRecoveryLatencyMillis = 9; + int nativeDocumentStoreDataStatus = + InitializeStatsProto.DocumentStoreDataStatus.NO_DATA_LOSS_VALUE; + int nativeNumDocuments = 11; + int nativeNumSchemaTypes = 12; + InitializeStatsProto.Builder nativeInitBuilder = + InitializeStatsProto.newBuilder() + .setLatencyMs(nativeLatencyMillis) + .setDocumentStoreRecoveryCause( + InitializeStatsProto.RecoveryCause.forNumber( + nativeDocumentStoreRecoveryCause)) + .setIndexRestorationCause( + InitializeStatsProto.RecoveryCause.forNumber( + nativeIndexRestorationCause)) + .setSchemaStoreRecoveryCause( + InitializeStatsProto.RecoveryCause.forNumber( + nativeSchemaStoreRecoveryCause)) + .setDocumentStoreRecoveryLatencyMs(nativeDocumentStoreRecoveryLatencyMillis) + .setIndexRestorationLatencyMs(nativeIndexRestorationLatencyMillis) + .setSchemaStoreRecoveryLatencyMs(nativeSchemaStoreRecoveryLatencyMillis) + .setDocumentStoreDataStatus( + InitializeStatsProto.DocumentStoreDataStatus.forNumber( + nativeDocumentStoreDataStatus)) + .setNumDocuments(nativeNumDocuments) + .setNumSchemaTypes(nativeNumSchemaTypes); + InitializeStats.Builder initBuilder = new InitializeStats.Builder(); + + AppSearchLoggerHelper.copyNativeStats(nativeInitBuilder.build(), initBuilder); + + InitializeStats iStats = initBuilder.build(); + assertThat(iStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(iStats.getDocumentStoreRecoveryCause()) + .isEqualTo(nativeDocumentStoreRecoveryCause); + assertThat(iStats.getIndexRestorationCause()).isEqualTo(nativeIndexRestorationCause); + assertThat(iStats.getSchemaStoreRecoveryCause()).isEqualTo(nativeSchemaStoreRecoveryCause); + assertThat(iStats.getDocumentStoreRecoveryLatencyMillis()) + .isEqualTo(nativeDocumentStoreRecoveryLatencyMillis); + assertThat(iStats.getIndexRestorationLatencyMillis()) + .isEqualTo(nativeIndexRestorationLatencyMillis); + assertThat(iStats.getSchemaStoreRecoveryLatencyMillis()) + .isEqualTo(nativeSchemaStoreRecoveryLatencyMillis); + assertThat(iStats.getDocumentStoreDataStatus()).isEqualTo(nativeDocumentStoreDataStatus); + assertThat(iStats.getDocumentCount()).isEqualTo(nativeNumDocuments); + assertThat(iStats.getSchemaTypeCount()).isEqualTo(nativeNumSchemaTypes); } @Test @@ -111,10 +189,97 @@ public class AppSearchLoggerTest { assertThat(pStats.getNativeExceededMaxNumTokens()).isEqualTo(nativeExceededMaxNumTokens); } + @Test + public void testAppSearchLoggerHelper_testCopyNativeStats_search() { + int nativeLatencyMillis = 4; + int nativeNumTerms = 5; + // TODO(b/185804196) query length needs to be added in the native stats. + // int nativeQueryLength = 6; + int nativeNumNamespacesFiltered = 7; + int nativeNumSchemaTypesFiltered = 8; + int nativeRequestedPageSize = 9; + int nativeNumResultsReturnedCurrentPage = 10; + boolean nativeIsFirstPage = true; + int nativeParseQueryLatencyMillis = 11; + int nativeRankingStrategy = ScoringSpecProto.RankingStrategy.Code.CREATION_TIMESTAMP_VALUE; + int nativeNumDocumentsScored = 13; + int nativeScoringLatencyMillis = 14; + int nativeRankingLatencyMillis = 15; + int nativeNumResultsWithSnippets = 16; + int nativeDocumentRetrievingLatencyMillis = 17; + QueryStatsProto nativeQueryStats = + QueryStatsProto.newBuilder() + .setLatencyMs(nativeLatencyMillis) + .setNumTerms(nativeNumTerms) + .setNumNamespacesFiltered(nativeNumNamespacesFiltered) + .setNumSchemaTypesFiltered(nativeNumSchemaTypesFiltered) + .setRequestedPageSize(nativeRequestedPageSize) + .setNumResultsReturnedCurrentPage(nativeNumResultsReturnedCurrentPage) + .setIsFirstPage(nativeIsFirstPage) + .setParseQueryLatencyMs(nativeParseQueryLatencyMillis) + .setRankingStrategy( + ScoringSpecProto.RankingStrategy.Code.forNumber( + nativeRankingStrategy)) + .setNumDocumentsScored(nativeNumDocumentsScored) + .setScoringLatencyMs(nativeScoringLatencyMillis) + .setRankingLatencyMs(nativeRankingLatencyMillis) + .setNumResultsWithSnippets(nativeNumResultsWithSnippets) + .setDocumentRetrievalLatencyMs(nativeDocumentRetrievingLatencyMillis) + .build(); + SearchStats.Builder qBuilder = + new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_LOCAL, "packageName") + .setDatabase("database"); + + AppSearchLoggerHelper.copyNativeStats(nativeQueryStats, qBuilder); + + SearchStats sStats = qBuilder.build(); + assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(sStats.getTermCount()).isEqualTo(nativeNumTerms); + // assertThat(sStats.getNativeQueryLength()).isEqualTo(nativeQueryLength); + assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(nativeNumNamespacesFiltered); + assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(nativeNumSchemaTypesFiltered); + assertThat(sStats.getRequestedPageSize()).isEqualTo(nativeRequestedPageSize); + assertThat(sStats.getCurrentPageReturnedResultCount()) + .isEqualTo(nativeNumResultsReturnedCurrentPage); + assertThat(sStats.isFirstPage()).isTrue(); + assertThat(sStats.getParseQueryLatencyMillis()).isEqualTo(nativeParseQueryLatencyMillis); + assertThat(sStats.getRankingStrategy()).isEqualTo(nativeRankingStrategy); + assertThat(sStats.getScoredDocumentCount()).isEqualTo(nativeNumDocumentsScored); + assertThat(sStats.getScoringLatencyMillis()).isEqualTo(nativeScoringLatencyMillis); + assertThat(sStats.getRankingLatencyMillis()).isEqualTo(nativeRankingLatencyMillis); + assertThat(sStats.getResultWithSnippetsCount()).isEqualTo(nativeNumResultsWithSnippets); + assertThat(sStats.getDocumentRetrievingLatencyMillis()) + .isEqualTo(nativeDocumentRetrievingLatencyMillis); + } + // // Testing actual logging // @Test + public void testLoggingStats_initialize() throws Exception { + Context context = ApplicationProvider.getApplicationContext(); + + AppSearchImpl appSearchImpl = + AppSearchImpl.create( + mTemporaryFolder.newFolder(), + context, + VisibilityStore.NO_OP_USER_ID, + /*globalQuerierPackage=*/ context.getPackageName(), + mLogger); + + InitializeStats iStats = mLogger.mInitializeStats; + assertThat(iStats).isNotNull(); + assertThat(iStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK); + assertThat(iStats.getTotalLatencyMillis()).isGreaterThan(0); + assertThat(iStats.hasDeSync()).isFalse(); + assertThat(iStats.getNativeLatencyMillis()).isGreaterThan(0); + assertThat(iStats.getDocumentStoreDataStatus()) + .isEqualTo(InitializeStatsProto.DocumentStoreDataStatus.NO_DATA_LOSS_VALUE); + assertThat(iStats.getDocumentCount()).isEqualTo(0); + assertThat(iStats.getSchemaTypeCount()).isEqualTo(0); + } + + @Test public void testLoggingStats_putDocument() throws Exception { // Insert schema final String testPackageName = "testPackage"; @@ -141,4 +306,53 @@ public class AppSearchLoggerTest { // The rest of native stats have been tested in testCopyNativeStats assertThat(pStats.getNativeDocumentSizeBytes()).isGreaterThan(0); } + + @Test + public void testLoggingStats_search() throws Exception { + // Insert schema + final String testPackageName = "testPackage"; + final String testDatabase = "testDatabase"; + List<AppSearchSchema> schemas = + Collections.singletonList(new AppSearchSchema.Builder("type").build()); + mAppSearchImpl.setSchema( + testPackageName, + testDatabase, + schemas, + /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), + /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*forceOverride=*/ false, + /*version=*/ 0); + GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build(); + mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger); + + // No query filters specified. package2 should only get its own documents back. + SearchSpec searchSpec = + new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); + SearchResultPage searchResultPage = + mAppSearchImpl.query( + testPackageName, + testDatabase, + /*QueryExpression=*/ "", + searchSpec, + /*logger=*/ mLogger); + + assertThat(searchResultPage.getResults()).hasSize(1); + assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document); + + SearchStats sStats = mLogger.mSearchStats; + + assertThat(sStats).isNotNull(); + assertThat(sStats.getPackageName()).isEqualTo(testPackageName); + assertThat(sStats.getDatabase()).isEqualTo(testDatabase); + assertThat(sStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK); + assertThat(sStats.getTotalLatencyMillis()).isGreaterThan(0); + assertThat(sStats.getVisibilityScope()).isEqualTo(SearchStats.VISIBILITY_SCOPE_LOCAL); + assertThat(sStats.getTermCount()).isEqualTo(0); + // assertThat(sStats.getNativeQueryLength()).isEqualTo(0); + assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(1); + assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(1); + assertThat(sStats.getCurrentPageReturnedResultCount()).isEqualTo(1); + assertThat(sStats.isFirstPage()).isTrue(); + assertThat(sStats.getScoredDocumentCount()).isEqualTo(1); + } } diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java index 8dbf249c4e96..5c7ccfc458b2 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java @@ -134,4 +134,135 @@ public class AppSearchStatsTest { assertThat(pStats.getNativeNumTokensIndexed()).isEqualTo(nativeNumTokensIndexed); assertThat(pStats.getNativeExceededMaxNumTokens()).isEqualTo(nativeExceededMaxNumTokens); } + + @Test + public void testAppSearchStats_InitializeStats() { + int prepareSchemaAndNamespacesLatencyMillis = 1; + int prepareVisibilityFileLatencyMillis = 2; + int nativeLatencyMillis = 3; + int nativeDocumentStoreRecoveryCause = 4; + int nativeIndexRestorationCause = 5; + int nativeSchemaStoreRecoveryCause = 6; + int nativeDocumentStoreRecoveryLatencyMillis = 7; + int nativeIndexRestorationLatencyMillis = 8; + int nativeSchemaStoreRecoveryLatencyMillis = 9; + int nativeDocumentStoreDataStatus = 10; + int nativeNumDocuments = 11; + int nativeNumSchemaTypes = 12; + + final InitializeStats.Builder iStatsBuilder = + new InitializeStats.Builder() + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .setHasDeSync(/* hasDeSyncs= */ true) + .setPrepareSchemaAndNamespacesLatencyMillis( + prepareSchemaAndNamespacesLatencyMillis) + .setPrepareVisibilityStoreLatencyMillis(prepareVisibilityFileLatencyMillis) + .setNativeLatencyMillis(nativeLatencyMillis) + .setDocumentStoreRecoveryCause(nativeDocumentStoreRecoveryCause) + .setIndexRestorationCause(nativeIndexRestorationCause) + .setSchemaStoreRecoveryCause(nativeSchemaStoreRecoveryCause) + .setDocumentStoreRecoveryLatencyMillis( + nativeDocumentStoreRecoveryLatencyMillis) + .setIndexRestorationLatencyMillis(nativeIndexRestorationLatencyMillis) + .setSchemaStoreRecoveryLatencyMillis(nativeSchemaStoreRecoveryLatencyMillis) + .setDocumentStoreDataStatus(nativeDocumentStoreDataStatus) + .setDocumentCount(nativeNumDocuments) + .setSchemaTypeCount(nativeNumSchemaTypes); + final InitializeStats iStats = iStatsBuilder.build(); + + assertThat(iStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(iStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + assertThat(iStats.hasDeSync()).isTrue(); + assertThat(iStats.getPrepareSchemaAndNamespacesLatencyMillis()) + .isEqualTo(prepareSchemaAndNamespacesLatencyMillis); + assertThat(iStats.getPrepareVisibilityStoreLatencyMillis()) + .isEqualTo(prepareVisibilityFileLatencyMillis); + assertThat(iStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(iStats.getDocumentStoreRecoveryCause()) + .isEqualTo(nativeDocumentStoreRecoveryCause); + assertThat(iStats.getIndexRestorationCause()).isEqualTo(nativeIndexRestorationCause); + assertThat(iStats.getSchemaStoreRecoveryCause()).isEqualTo(nativeSchemaStoreRecoveryCause); + assertThat(iStats.getDocumentStoreRecoveryLatencyMillis()) + .isEqualTo(nativeDocumentStoreRecoveryLatencyMillis); + assertThat(iStats.getIndexRestorationLatencyMillis()) + .isEqualTo(nativeIndexRestorationLatencyMillis); + assertThat(iStats.getSchemaStoreRecoveryLatencyMillis()) + .isEqualTo(nativeSchemaStoreRecoveryLatencyMillis); + assertThat(iStats.getDocumentStoreDataStatus()).isEqualTo(nativeDocumentStoreDataStatus); + assertThat(iStats.getDocumentCount()).isEqualTo(nativeNumDocuments); + assertThat(iStats.getSchemaTypeCount()).isEqualTo(nativeNumSchemaTypes); + } + + @Test + public void testAppSearchStats_SearchStats() { + int rewriteSearchSpecLatencyMillis = 1; + int rewriteSearchResultLatencyMillis = 2; + int visibilityScope = SearchStats.VISIBILITY_SCOPE_LOCAL; + int nativeLatencyMillis = 4; + int nativeNumTerms = 5; + int nativeQueryLength = 6; + int nativeNumNamespacesFiltered = 7; + int nativeNumSchemaTypesFiltered = 8; + int nativeRequestedPageSize = 9; + int nativeNumResultsReturnedCurrentPage = 10; + boolean nativeIsFirstPage = true; + int nativeParseQueryLatencyMillis = 11; + int nativeRankingStrategy = 12; + int nativeNumDocumentsScored = 13; + int nativeScoringLatencyMillis = 14; + int nativeRankingLatencyMillis = 15; + int nativeNumResultsSnippeted = 16; + int nativeDocumentRetrievingLatencyMillis = 17; + final SearchStats.Builder sStatsBuilder = + new SearchStats.Builder(visibilityScope, TEST_PACKAGE_NAME) + .setDatabase(TEST_DATA_BASE) + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .setRewriteSearchSpecLatencyMillis(rewriteSearchSpecLatencyMillis) + .setRewriteSearchResultLatencyMillis(rewriteSearchResultLatencyMillis) + .setNativeLatencyMillis(nativeLatencyMillis) + .setTermCount(nativeNumTerms) + .setQueryLength(nativeQueryLength) + .setFilteredNamespaceCount(nativeNumNamespacesFiltered) + .setFilteredSchemaTypeCount(nativeNumSchemaTypesFiltered) + .setRequestedPageSize(nativeRequestedPageSize) + .setCurrentPageReturnedResultCount(nativeNumResultsReturnedCurrentPage) + .setIsFirstPage(nativeIsFirstPage) + .setParseQueryLatencyMillis(nativeParseQueryLatencyMillis) + .setRankingStrategy(nativeRankingStrategy) + .setScoredDocumentCount(nativeNumDocumentsScored) + .setScoringLatencyMillis(nativeScoringLatencyMillis) + .setRankingLatencyMillis(nativeRankingLatencyMillis) + .setResultWithSnippetsCount(nativeNumResultsSnippeted) + .setDocumentRetrievingLatencyMillis(nativeDocumentRetrievingLatencyMillis); + final SearchStats sStats = sStatsBuilder.build(); + + assertThat(sStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME); + assertThat(sStats.getDatabase()).isEqualTo(TEST_DATA_BASE); + assertThat(sStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(sStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + assertThat(sStats.getRewriteSearchSpecLatencyMillis()) + .isEqualTo(rewriteSearchSpecLatencyMillis); + assertThat(sStats.getRewriteSearchResultLatencyMillis()) + .isEqualTo(rewriteSearchResultLatencyMillis); + assertThat(sStats.getVisibilityScope()).isEqualTo(visibilityScope); + assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(sStats.getTermCount()).isEqualTo(nativeNumTerms); + assertThat(sStats.getQueryLength()).isEqualTo(nativeQueryLength); + assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(nativeNumNamespacesFiltered); + assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(nativeNumSchemaTypesFiltered); + assertThat(sStats.getRequestedPageSize()).isEqualTo(nativeRequestedPageSize); + assertThat(sStats.getCurrentPageReturnedResultCount()) + .isEqualTo(nativeNumResultsReturnedCurrentPage); + assertThat(sStats.isFirstPage()).isTrue(); + assertThat(sStats.getParseQueryLatencyMillis()).isEqualTo(nativeParseQueryLatencyMillis); + assertThat(sStats.getRankingStrategy()).isEqualTo(nativeRankingStrategy); + assertThat(sStats.getScoredDocumentCount()).isEqualTo(nativeNumDocumentsScored); + assertThat(sStats.getScoringLatencyMillis()).isEqualTo(nativeScoringLatencyMillis); + assertThat(sStats.getRankingLatencyMillis()).isEqualTo(nativeRankingLatencyMillis); + assertThat(sStats.getResultWithSnippetsCount()).isEqualTo(nativeNumResultsSnippeted); + assertThat(sStats.getDocumentRetrievingLatencyMillis()) + .isEqualTo(nativeDocumentRetrievingLatencyMillis); + } } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java index 10a7a5000317..6f0c8e1004c4 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java @@ -31,11 +31,14 @@ import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.PromptInfo; +import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceService; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintService; import android.hardware.iris.IIrisService; import android.os.Binder; @@ -45,11 +48,17 @@ import android.platform.test.annotations.Presubmit; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; +import com.android.internal.R; + import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.List; + @Presubmit @SmallTest public class AuthServiceTest { @@ -62,6 +71,8 @@ public class AuthServiceTest { @Mock private Context mContext; @Mock + private Resources mResources; + @Mock private PackageManager mPackageManager; @Mock IBiometricServiceReceiver mReceiver; @@ -77,6 +88,10 @@ public class AuthServiceTest { IFaceService mFaceService; @Mock AppOpsManager mAppOpsManager; + @Captor + private ArgumentCaptor<List<FingerprintSensorPropertiesInternal>> mFingerprintPropsCaptor; + @Captor + private ArgumentCaptor<List<FaceSensorPropertiesInternal>> mFacePropsCaptor; @Before public void setUp() { @@ -89,7 +104,16 @@ public class AuthServiceTest { "2:8:15", // ID2:Face:Strong }; + when(mResources.getIntArray(eq(R.array.config_udfps_sensor_props))).thenReturn(new int[0]); + when(mResources.getBoolean(eq(R.bool.config_is_powerbutton_fps))).thenReturn(false); + when(mResources.getInteger(eq(R.integer.config_fingerprintMaxTemplatesPerUser))).thenReturn( + 1); + when(mResources.getBoolean(eq(R.bool.config_faceAuthSupportsSelfIllumination))).thenReturn( + false); + when(mResources.getInteger(eq(R.integer.config_faceMaxTemplatesPerUser))).thenReturn(1); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mContext.getResources()).thenReturn(mResources); when(mInjector.getBiometricService()).thenReturn(mBiometricService); when(mInjector.getConfiguration(any())).thenReturn(config); when(mInjector.getFingerprintService()).thenReturn(mFingerprintService); @@ -119,11 +143,18 @@ public class AuthServiceTest { } @Test - public void testRegisterAuthenticator_initializesConfiguration() throws Exception { + public void testRegisterAuthenticator_registerAuthenticators() throws Exception { + final int fingerprintId = 0; + final int fingerprintStrength = 15; + + final int faceId = 1; + final int faceStrength = 4095; final String[] config = { - "0:2:15", // ID0:Fingerprint:Strong - "1:8:4095", // ID2:Face:Convenience + // ID0:Fingerprint:Strong + String.format("%d:2:%d", fingerprintId, fingerprintStrength), + // ID2:Face:Convenience + String.format("%d:8:%d", faceId, faceStrength) }; when(mInjector.getConfiguration(any())).thenReturn(config); @@ -131,15 +162,18 @@ public class AuthServiceTest { mAuthService = new AuthService(mContext, mInjector); mAuthService.onStart(); - final int fingerprintId = 0; - final int faceId = 1; - - final int fingerprintStrength = 15; - final int faceStrength = 4095; - - verify(mFingerprintService).initializeConfiguration(eq(fingerprintId), - eq(fingerprintStrength)); - verify(mFaceService).initializeConfiguration(eq(faceId), eq(faceStrength)); + verify(mFingerprintService).registerAuthenticators(mFingerprintPropsCaptor.capture()); + final FingerprintSensorPropertiesInternal fingerprintProp = + mFingerprintPropsCaptor.getValue().get(0); + assertEquals(fingerprintProp.sensorId, fingerprintId); + assertEquals(fingerprintProp.sensorStrength, + Utils.authenticatorStrengthToPropertyStrength(fingerprintStrength)); + + verify(mFaceService).registerAuthenticators(mFacePropsCaptor.capture()); + final FaceSensorPropertiesInternal faceProp = mFacePropsCaptor.getValue().get(0); + assertEquals(faceProp.sensorId, faceId); + assertEquals(faceProp.sensorStrength, + Utils.authenticatorStrengthToPropertyStrength(faceStrength)); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java index 392535e8eea1..0b59be65b887 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java @@ -22,7 +22,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.ComponentInfoInternal; +import android.hardware.biometrics.SensorProperties; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; import android.os.Binder; import android.os.IBinder; import android.os.UserManager; @@ -40,6 +43,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.List; @Presubmit @SmallTest @@ -71,9 +75,18 @@ public class Face10Test { when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>()); mLockoutResetDispatcher = new LockoutResetDispatcher(mContext); - mFace10 = new Face10(mContext, SENSOR_ID, BiometricManager.Authenticators.BIOMETRIC_STRONG, - mLockoutResetDispatcher, false /* supportsSelfIllumination */, - 1 /* maxTemplatesAllowed */, mScheduler); + + final int maxEnrollmentsPerUser = 1; + final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); + final boolean supportsFaceDetection = false; + final boolean supportsSelfIllumination = false; + final boolean resetLockoutRequiresChallenge = false; + final FaceSensorPropertiesInternal sensorProps = new FaceSensorPropertiesInternal(SENSOR_ID, + SensorProperties.STRENGTH_STRONG, maxEnrollmentsPerUser, componentInfo, + FaceSensorProperties.TYPE_UNKNOWN, supportsFaceDetection, supportsSelfIllumination, + resetLockoutRequiresChallenge); + + mFace10 = new Face10(mContext, sensorProps, mLockoutResetDispatcher, mScheduler); mBinder = new Binder(); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java index 904ade82a51f..0a0dcc97272b 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java @@ -25,8 +25,10 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; -import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; +import android.hardware.fingerprint.FingerprintSensorProperties; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Handler; import android.os.Looper; import android.os.UserManager; @@ -46,6 +48,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.List; @Presubmit @SmallTest @@ -83,10 +86,18 @@ public class Fingerprint21Test { .thenReturn(5); mLockoutResetDispatcher = new LockoutResetDispatcher(mContext); - mFingerprint21 = new TestableFingerprint21(mContext, mScheduler, - new Handler(Looper.getMainLooper()), SENSOR_ID, - BiometricManager.Authenticators.BIOMETRIC_WEAK, mLockoutResetDispatcher, - mHalResultController); + + final int maxEnrollmentsPerUser = 1; + final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); + final boolean resetLockoutRequiresHardwareAuthToken = false; + final FingerprintSensorPropertiesInternal sensorProps = + new FingerprintSensorPropertiesInternal(SENSOR_ID, + FingerprintSensorProperties.STRENGTH_WEAK, maxEnrollmentsPerUser, + componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN, + resetLockoutRequiresHardwareAuthToken); + + mFingerprint21 = new TestableFingerprint21(mContext, sensorProps, mScheduler, + new Handler(Looper.getMainLooper()), mLockoutResetDispatcher, mHalResultController); } @Test @@ -107,12 +118,11 @@ public class Fingerprint21Test { private static class TestableFingerprint21 extends Fingerprint21 { TestableFingerprint21(@NonNull Context context, - @NonNull BiometricScheduler scheduler, - @NonNull Handler handler, int sensorId, int strength, + @NonNull FingerprintSensorPropertiesInternal sensorProps, + @NonNull BiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull HalResultController controller) { - super(context, scheduler, handler, sensorId, strength, lockoutResetDispatcher, - controller); + super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller); } @Override diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java index 81570a10fc13..fe0df5818651 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java @@ -253,6 +253,8 @@ public abstract class DpmTestBase { doReturn(new String[] {admin.getPackageName()}).when(mServices.ipackageManager) .getPackagesForUid(eq(packageUid)); + doReturn(new String[] {admin.getPackageName()}).when(mServices.packageManager) + .getPackagesForUid(eq(packageUid)); // Set up getPackageInfo(). markPackageAsInstalled(admin.getPackageName(), ai, UserHandle.getUserId(packageUid)); } diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java index d784a221fbd7..8279624f6b97 100644 --- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -27,17 +27,20 @@ import static org.junit.Assert.assertNotEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.PropertyInvalidatedCache; import android.content.Context; +import android.content.res.Resources; +import android.os.Handler; import android.os.Parcel; import android.os.Process; +import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import android.view.Display; import android.view.DisplayAddress; import android.view.DisplayInfo; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -61,9 +64,12 @@ public class LogicalDisplayMapperTest { private DisplayDeviceRepository mDisplayDeviceRepo; private LogicalDisplayMapper mLogicalDisplayMapper; - private Context mContext; + private TestLooper mLooper; + private Handler mHandler; @Mock LogicalDisplayMapper.Listener mListenerMock; + @Mock Context mContextMock; + @Mock Resources mResourcesMock; @Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor; @@ -73,7 +79,6 @@ public class LogicalDisplayMapperTest { System.setProperty("dexmaker.share_classloader", "true"); MockitoAnnotations.initMocks(this); - mContext = InstrumentationRegistry.getContext(); mDisplayDeviceRepo = new DisplayDeviceRepository( new DisplayManagerService.SyncRoot(), new PersistentDataStore(new PersistentDataStore.Injector() { @@ -94,7 +99,15 @@ public class LogicalDisplayMapperTest { // Disable binder caches in this process. PropertyInvalidatedCache.disableForTestMode(); - mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo, mListenerMock); + when(mContextMock.getResources()).thenReturn(mResourcesMock); + when(mResourcesMock.getBoolean( + com.android.internal.R.bool.config_supportsConcurrentInternalDisplays)) + .thenReturn(true); + + mLooper = new TestLooper(); + mHandler = new Handler(mLooper.getLooper()); + mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mDisplayDeviceRepo, + mListenerMock, new DisplayManagerService.SyncRoot(), mHandler); } @@ -299,7 +312,7 @@ public class LogicalDisplayMapperTest { private DisplayDeviceInfo mSentInfo; TestDisplayDevice() { - super(null, null, "test_display_" + sUniqueTestDisplayId++, mContext); + super(null, null, "test_display_" + sUniqueTestDisplayId++, mContextMock); mInfo = new DisplayDeviceInfo(); } 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 b1582be4532f..765c13a98ac0 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 @@ -963,7 +963,7 @@ public final class UpdatableFontDirTest { parser.setInput(is, "UTF-8"); parser.nextTag(); - FontConfig.FontFamily fontFamily = FontListParser.readFamily(parser, "", null); + FontConfig.FontFamily fontFamily = FontListParser.readFamily(parser, "", null, true); List<FontUpdateRequest.Font> fonts = new ArrayList<>(); for (FontConfig.Font font : fontFamily.getFontList()) { String name = font.getFile().getName(); 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 ef7b274eeb83..011b8f899753 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java @@ -138,6 +138,7 @@ public class DevicePowerStatusActionTest { mDevicePowerStatusAction = DevicePowerStatusAction.create(mPlaybackDevice, ADDR_TV, mCallbackMock); mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); } @Test 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 80da6961cf16..a29a76b438df 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -60,6 +60,7 @@ import java.util.concurrent.TimeUnit; @RunWith(JUnit4.class) /** Tests for {@link HdmiCecLocalDevicePlayback} class. */ public class HdmiCecLocalDevicePlaybackTest { + private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1; private static final int PORT_1 = 1; private static final HdmiDeviceInfo INFO_TV = new HdmiDeviceInfo( @@ -1045,6 +1046,10 @@ public class HdmiCecLocalDevicePlaybackTest { assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue(); // 4. DUT turned off. mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF); + // TODO(b/184939731): remove waiting times once pending actions no longer block <Standby> + mTestLooper.moveTimeForward(TIMEOUT_MS); + mTestLooper.dispatchAll(); + mTestLooper.moveTimeForward(TIMEOUT_MS); mTestLooper.dispatchAll(); HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby( mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST); @@ -1502,6 +1507,7 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void queryDisplayStatus() { + mTestLooper.moveTimeForward(TIMEOUT_MS); mHdmiControlService.queryDisplayStatus(new IHdmiControlCallback.Stub() { @Override public void onComplete(int result) { @@ -1618,6 +1624,12 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void shouldHandleTvPowerKey_CecDisabled() { + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + HdmiCecMessage reportPowerStatusMessage = HdmiCecMessageBuilder.buildReportPowerStatus( + Constants.ADDR_TV, mPlaybackLogicalAddress, HdmiControlManager.POWER_STATUS_ON); + mNativeWrapper.onCecMessage(reportPowerStatusMessage); + mTestLooper.dispatchAll(); + mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); @@ -1626,6 +1638,12 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void shouldHandleTvPowerKey_PowerControlModeNone() { + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + HdmiCecMessage reportPowerStatusMessage = HdmiCecMessageBuilder.buildReportPowerStatus( + Constants.ADDR_TV, mPlaybackLogicalAddress, HdmiControlManager.POWER_STATUS_ON); + mNativeWrapper.onCecMessage(reportPowerStatusMessage); + mTestLooper.dispatchAll(); + mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue( HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE, HdmiControlManager.POWER_CONTROL_MODE_NONE); @@ -1633,7 +1651,22 @@ public class HdmiCecLocalDevicePlaybackTest { } @Test + public void shouldHandleTvPowerKey_CecNotAvailable() { + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + // TV doesn't report its power status + mTestLooper.moveTimeForward(TIMEOUT_MS); + mTestLooper.dispatchAll(); + assertThat(mHdmiControlService.shouldHandleTvPowerKey()).isFalse(); + } + + @Test public void shouldHandleTvPowerKey_CecEnabled_PowerControlModeTv() { + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + HdmiCecMessage reportPowerStatusMessage = HdmiCecMessageBuilder.buildReportPowerStatus( + Constants.ADDR_TV, mPlaybackLogicalAddress, HdmiControlManager.POWER_STATUS_ON); + mNativeWrapper.onCecMessage(reportPowerStatusMessage); + mTestLooper.dispatchAll(); + mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); 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 950b8a254007..c7a508a9d626 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java @@ -61,6 +61,7 @@ import java.util.ArrayList; @RunWith(JUnit4.class) /** Tests for {@link HdmiCecLocalDeviceTv} class. */ public class HdmiCecLocalDeviceTvTest { + private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1; private HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; @@ -294,6 +295,10 @@ public class HdmiCecLocalDeviceTvTest { HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED); mTestLooper.dispatchAll(); mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF); + // TODO(184939731): remove waiting times once pending actions no longer block <Standby> + mTestLooper.moveTimeForward(TIMEOUT_MS); + mTestLooper.dispatchAll(); + mTestLooper.moveTimeForward(TIMEOUT_MS); mTestLooper.dispatchAll(); HdmiCecMessage standby = HdmiCecMessageBuilder.buildStandby(ADDR_TV, ADDR_BROADCAST); assertThat(mNativeWrapper.getResultMessages()).contains(standby); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java index 5b019207688f..2307a85fe9cd 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java @@ -392,9 +392,9 @@ public class HdmiCecMessageValidatorTest { @Test public void isValid_giveFeatures() { assertMessageValidity("40:A5").isEqualTo(OK); + assertMessageValidity("F0:A5").isEqualTo(OK); assertMessageValidity("4F:A5").isEqualTo(ERROR_DESTINATION); - assertMessageValidity("F0:A5").isEqualTo(ERROR_SOURCE); } @Test diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java index d74bff2837ce..48931739d9cf 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java @@ -142,6 +142,7 @@ public class OneTouchPlayActionTest { mPhysicalAddress = 0x2000; mNativeWrapper.setPhysicalAddress(mPhysicalAddress); mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); } private OneTouchPlayAction createOneTouchPlayAction(HdmiCecLocalDevicePlayback device, @@ -161,6 +162,7 @@ public class OneTouchPlayActionTest { mLocalDevices.add(playbackDevice); mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); TestActionTimer actionTimer = new TestActionTimer(); TestCallback callback = new TestCallback(); @@ -203,6 +205,7 @@ public class OneTouchPlayActionTest { mLocalDevices.add(playbackDevice); mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); TestActionTimer actionTimer = new TestActionTimer(); TestCallback callback = new TestCallback(); @@ -245,6 +248,7 @@ public class OneTouchPlayActionTest { mLocalDevices.add(playbackDevice); mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); TestActionTimer actionTimer = new TestActionTimer(); TestCallback callback = new TestCallback(); @@ -297,6 +301,7 @@ public class OneTouchPlayActionTest { mLocalDevices.add(playbackDevice); mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); TestActionTimer actionTimer = new TestActionTimer(); TestCallback callback = new TestCallback(); @@ -342,6 +347,7 @@ public class OneTouchPlayActionTest { mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV, HdmiControlManager.POWER_STATUS_ON); mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); TestActionTimer actionTimer = new TestActionTimer(); TestCallback callback = new TestCallback(); @@ -376,6 +382,7 @@ public class OneTouchPlayActionTest { mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV, HdmiControlManager.POWER_STATUS_UNKNOWN); mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); TestActionTimer actionTimer = new TestActionTimer(); TestCallback callback = new TestCallback(); @@ -420,6 +427,7 @@ public class OneTouchPlayActionTest { mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV, HdmiControlManager.POWER_STATUS_STANDBY); mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); TestActionTimer actionTimer = new TestActionTimer(); TestCallback callback = new TestCallback(); diff --git a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java index f0a9a0089ec9..75aacd148011 100644 --- a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java @@ -47,6 +47,9 @@ import org.mockito.MockitoAnnotations; @SmallTest public class LightsServiceTest { + private static final int HIGH_PRIORITY = Integer.MAX_VALUE; + private static final int DEFAULT_PRIORITY = 0; + private final ILights mHal = new ILights.Stub() { @Override public void setLightState(int id, HwLightState state) { @@ -188,4 +191,30 @@ public class LightsServiceTest { // Then the light should turn back off. assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0); } + + @Test + public void testControlLights_higherPriorityCallerWinsContention() throws Exception { + LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper()); + LightsManager manager = new SystemLightsManager(mContext, service.mManagerService); + Light micLight = manager.getLights().get(0); + + // The light should begin by being off. + assertThat(manager.getLightState(micLight).getColor()).isEqualTo(TRANSPARENT); + + try (LightsManager.LightsSession session1 = manager.openSession(DEFAULT_PRIORITY)) { + try (LightsManager.LightsSession session2 = manager.openSession(HIGH_PRIORITY)) { + // When session1 and session2 both request the same light: + session1.requestLights( + new Builder().addLight(micLight, new LightState(BLUE)).build()); + session2.requestLights( + new Builder().addLight(micLight, new LightState(WHITE)).build()); + // Then session2 should win because it has a higher priority. + assertThat(manager.getLightState(micLight).getColor()).isEqualTo(WHITE); + } + // Then session1 should have its request go into effect. + assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLUE); + } + // Then the light should turn off because there are no more sessions. + assertThat(manager.getLightState(micLight).getColor()).isEqualTo(TRANSPARENT); + } } 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 5d60a897b9a6..807ead3f5832 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -155,7 +155,8 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override - public ManagedProfilePasswordCache getManagedProfilePasswordCache() { + public ManagedProfilePasswordCache getManagedProfilePasswordCache( + java.security.KeyStore ks) { return mock(ManagedProfilePasswordCache.class); } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index c16e49899dc2..ec5228fec3f3 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -108,6 +108,7 @@ import com.android.server.pm.ShortcutService.FileOutputStreamWithPath; import com.android.server.pm.ShortcutUser.PackageWithUser; import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -416,8 +417,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mManager.pushDynamicShortcut(s1); assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1"); assertEquals(0, getCallerShortcut("s1").getRank()); + verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_0)); // Test push when other shortcuts exist + Mockito.reset(mMockUsageStatsManagerInternal); assertTrue(mManager.setDynamicShortcuts(list(s1, s2))); assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1", "s2"); mManager.pushDynamicShortcut(s3); @@ -426,25 +430,38 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(0, getCallerShortcut("s3").getRank()); assertEquals(1, getCallerShortcut("s1").getRank()); assertEquals(2, getCallerShortcut("s2").getRank()); + verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_0)); + verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s2"), eq(USER_0)); + verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s3"), eq(USER_0)); mInjectedCurrentTimeMillis += INTERVAL; // reset // Push with set rank + Mockito.reset(mMockUsageStatsManagerInternal); s4.setRank(2); mManager.pushDynamicShortcut(s4); assertEquals(2, getCallerShortcut("s4").getRank()); assertEquals(3, getCallerShortcut("s2").getRank()); + verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s4"), eq(USER_0)); // Push existing shortcut with set rank + Mockito.reset(mMockUsageStatsManagerInternal); final ShortcutInfo s4_2 = makeShortcut("s4"); s4_2.setRank(4); mManager.pushDynamicShortcut(s4_2); assertEquals(2, getCallerShortcut("s2").getRank()); assertEquals(3, getCallerShortcut("s4").getRank()); + verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s4"), eq(USER_0)); mInjectedCurrentTimeMillis += INTERVAL; // reset // Test push as last + Mockito.reset(mMockUsageStatsManagerInternal); mManager.pushDynamicShortcut(s5); assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1", "s2", "s3", "s4", "s5"); @@ -453,25 +470,34 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(2, getCallerShortcut("s1").getRank()); assertEquals(3, getCallerShortcut("s2").getRank()); assertEquals(4, getCallerShortcut("s4").getRank()); + verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s5"), eq(USER_0)); // Push when max has already reached + Mockito.reset(mMockUsageStatsManagerInternal); mManager.pushDynamicShortcut(s6); assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1", "s2", "s3", "s5", "s6"); assertEquals(0, getCallerShortcut("s6").getRank()); assertEquals(1, getCallerShortcut("s5").getRank()); assertEquals(4, getCallerShortcut("s2").getRank()); + verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s6"), eq(USER_0)); mInjectedCurrentTimeMillis += INTERVAL; // reset // Push with different activity + Mockito.reset(mMockUsageStatsManagerInternal); s7.setActivity(makeComponent(ShortcutActivity2.class)); mManager.pushDynamicShortcut(s7); assertEquals(makeComponent(ShortcutActivity2.class), getCallerShortcut("s7").getActivity()); assertEquals(0, getCallerShortcut("s7").getRank()); + verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s7"), eq(USER_0)); // Push to update shortcut with different activity + Mockito.reset(mMockUsageStatsManagerInternal); final ShortcutInfo s1_2 = makeShortcut("s1"); s1_2.setActivity(makeComponent(ShortcutActivity2.class)); s1_2.setRank(1); @@ -482,10 +508,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(1, getCallerShortcut("s5").getRank()); assertEquals(2, getCallerShortcut("s3").getRank()); assertEquals(3, getCallerShortcut("s2").getRank()); + verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_0)); mInjectedCurrentTimeMillis += INTERVAL; // reset // Test push when dropped shortcut is cached + Mockito.reset(mMockUsageStatsManagerInternal); s8.setLongLived(); s8.setRank(100); mManager.pushDynamicShortcut(s8); @@ -494,14 +523,19 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mInjectCheckAccessShortcutsPermission = true; mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s8"), HANDLE_USER_0, CACHE_OWNER_0); + verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s8"), eq(USER_0)); }); + Mockito.reset(mMockUsageStatsManagerInternal); mManager.pushDynamicShortcut(s9); assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1", "s2", "s3", "s5", "s6", "s7", "s9"); // Verify s13 stayed as cached assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s8"); + verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( + eq(CALLING_PACKAGE_1), eq("s9"), eq(USER_0)); } public void testUnlimitedCalls() { diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index ca7704950b51..7241fa00ecf7 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -2138,7 +2138,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { mManager.reportShortcutUsed("s2"); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_1), eq("s2"), eq(USER_10)); - }); runWithCaller(CALLING_PACKAGE_2, USER_10, () -> { // Try with a different package. @@ -2158,7 +2157,6 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { mManager.reportShortcutUsed("s3"); verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage( eq(CALLING_PACKAGE_2), eq("s3"), eq(USER_10)); - }); } diff --git a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java index d13687ce3254..4d2d2f1a4b7d 100644 --- a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java +++ b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java @@ -307,6 +307,56 @@ public final class DeviceStateProviderImplTest { assertEquals(1, mIntegerCaptor.getValue().intValue()); } + @Test + public void create_invalidSensor() throws Exception { + Sensor sensor = newSensor("sensor", Sensor.STRING_TYPE_HINGE_ANGLE); + when(mSensorManager.getSensorList(anyInt())).thenReturn(List.of()); + + String configString = "<device-state-config>\n" + + " <device-state>\n" + + " <identifier>1</identifier>\n" + + " <name>CLOSED</name>\n" + + " <conditions>\n" + + " <sensor>\n" + + " <type>" + sensor.getStringType() + "</type>\n" + + " <name>" + sensor.getName() + "</name>\n" + + " <value>\n" + + " <max>90</max>\n" + + " </value>\n" + + " </sensor>\n" + + " </conditions>\n" + + " </device-state>\n" + + " <device-state>\n" + + " <identifier>2</identifier>\n" + + " <name>HALF_OPENED</name>\n" + + " <conditions>\n" + + " <sensor>\n" + + " <type>" + sensor.getStringType() + "</type>\n" + + " <name>" + sensor.getName() + "</name>\n" + + " <value>\n" + + " <min-inclusive>90</min-inclusive>\n" + + " <max>180</max>\n" + + " </value>\n" + + " </sensor>\n" + + " </conditions>\n" + + " </device-state>\n" + + "</device-state-config>\n"; + DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString); + DeviceStateProviderImpl provider = DeviceStateProviderImpl.createFromConfig(mContext, + config); + + DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class); + provider.setListener(listener); + + verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture()); + assertArrayEquals( + new DeviceState[]{ new DeviceState(1, "CLOSED"), new DeviceState(2, "HALF_OPENED"), + }, mDeviceStateArrayCaptor.getValue()); + // onStateChanged() should be called because the provider could not find the sensor. + verify(listener).onStateChanged(mIntegerCaptor.capture()); + assertEquals(1, mIntegerCaptor.getValue().intValue()); + } + private static Sensor newSensor(String name, String type) throws Exception { Constructor<Sensor> constructor = Sensor.class.getDeclaredConstructor(); constructor.setAccessible(true); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java index 8c92a4732b17..0e615a6812fe 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java @@ -51,8 +51,6 @@ public class WindowOrientationListenerTest { private InputSensorInfo mMockInputSensorInfo; @Mock private SensorManager mMockSensorManager; - @Mock - private WindowManagerService mMockWindowManagerService; private TestableRotationResolver mFakeRotationResolverInternal; private com.android.server.wm.WindowOrientationListener mWindowOrientationListener; @@ -69,7 +67,7 @@ public class WindowOrientationListenerTest { mFakeRotationResolverInternal = new TestableRotationResolver(); doReturn(mMockSensorManager).when(mMockContext).getSystemService(Context.SENSOR_SERVICE); mWindowOrientationListener = new TestableWindowOrientationListener(mMockContext, - mMockHandler, mMockWindowManagerService); + mMockHandler); mWindowOrientationListener.mRotationResolverService = mFakeRotationResolverInternal; mFakeSensor = new Sensor(mMockInputSensorInfo); @@ -115,9 +113,8 @@ public class WindowOrientationListenerTest { final class TestableWindowOrientationListener extends WindowOrientationListener { - TestableWindowOrientationListener(Context context, Handler handler, - WindowManagerService service) { - super(context, handler, service); + TestableWindowOrientationListener(Context context, Handler handler) { + super(context, handler); this.mOrientationJudge = new OrientationSensorJudge(); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java index a2ad89edcf5e..a05fea2c8f70 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java @@ -144,15 +144,21 @@ public class ArchiveTest extends UiServiceTestCase { @Test public void testRemoveChannelNotifications() { List<String> expected = new ArrayList<>(); - for (int i = 0; i < SIZE; i++) { + // Add one extra notification to the beginning to test when 2 adjacent notifications will be + // removed in the same pass. + StatusBarNotification sbn0 = getNotification("pkg", 0, UserHandle.of(USER_CURRENT)); + mArchive.record(sbn0, REASON_CANCEL); + for (int i = 0; i < SIZE - 1; i++) { StatusBarNotification sbn = getNotification("pkg", i, UserHandle.of(USER_CURRENT)); mArchive.record(sbn, REASON_CANCEL); - if (i != 3) { - // Will delete notification for this user in channel "test3". + if (i != 0 && i != SIZE - 2) { + // Will delete notification for this user in channel "test0", and also the last + // element in the list. expected.add(sbn.getKey()); } } - mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test3"); + mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test0"); + mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test" + (SIZE - 2)); List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true)); assertThat(actual).hasSize(expected.size()); for (StatusBarNotification sbn : actual) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java index 9433bf28e237..6a8f602a8350 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java @@ -22,12 +22,15 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Person; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -72,6 +75,7 @@ public class NotificationComparatorTest extends UiServiceTestCase { private NotificationRecord mRecordMinCallNonInterruptive; private NotificationRecord mRecordMinCall; private NotificationRecord mRecordHighCall; + private NotificationRecord mRecordHighCallStyle; private NotificationRecord mRecordEmail; private NotificationRecord mRecordInlineReply; private NotificationRecord mRecordSms; @@ -90,9 +94,12 @@ public class NotificationComparatorTest extends UiServiceTestCase { int userId = UserHandle.myUserId(); when(mContext.getResources()).thenReturn(getContext().getResources()); + when(mContext.getTheme()).thenReturn(getContext().getTheme()); when(mContext.getContentResolver()).thenReturn(getContext().getContentResolver()); when(mContext.getPackageManager()).thenReturn(mPm); when(mContext.getSystemService(eq(Context.TELECOM_SERVICE))).thenReturn(mTm); + when(mContext.getString(anyInt())).thenCallRealMethod(); + when(mContext.getColor(anyInt())).thenCallRealMethod(); when(mTm.getDefaultDialerPackage()).thenReturn(callPkg); final ApplicationInfo legacy = new ApplicationInfo(); legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; @@ -137,6 +144,19 @@ public class NotificationComparatorTest extends UiServiceTestCase { new UserHandle(userId), "", 1999), getDefaultChannel()); mRecordHighCall.setSystemImportance(NotificationManager.IMPORTANCE_HIGH); + Notification nHighCallStyle = new Notification.Builder(mContext, TEST_CHANNEL_ID) + .setStyle(Notification.CallStyle.forOngoingCall( + new Person.Builder().setName("caller").build(), + mock(PendingIntent.class) + )) + .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) + .build(); + mRecordHighCallStyle = new NotificationRecord(mContext, new StatusBarNotification(callPkg, + callPkg, 1, "highCallStyle", callUid, callUid, nHighCallStyle, + new UserHandle(userId), "", 2000), getDefaultChannel()); + mRecordHighCallStyle.setSystemImportance(NotificationManager.IMPORTANCE_HIGH); + mRecordHighCallStyle.setInterruptive(true); + Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID) .setStyle(new Notification.MessagingStyle("sender!")).build(); mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2, @@ -236,6 +256,7 @@ public class NotificationComparatorTest extends UiServiceTestCase { final List<NotificationRecord> expected = new ArrayList<>(); expected.add(mRecordColorizedCall); expected.add(mRecordColorized); + expected.add(mRecordHighCallStyle); expected.add(mRecordHighCall); expected.add(mRecordInlineReply); if (mRecordSms != null) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 5743decbfe24..537bc2c7d52c 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -4730,6 +4730,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory() + throws RemoteException { + final NotificationRecord r = generateNotificationRecord( + mTestNotificationChannel, 1, null, true); + r.setInterruptive(true); + r.getSbn().getNotification().setSmallIcon(null); + mService.addNotification(r); + + mService.maybeRecordInterruptionLocked(r); + + verify(mAppUsageStats, times(1)).reportInterruptiveNotification( + anyString(), anyString(), anyInt()); + verify(mHistoryManager, never()).addNotification(any()); + } + + @Test public void testBubble() throws Exception { mBinderService.setBubblesAllowed(PKG, mUid, BUBBLE_PREFERENCE_NONE); assertFalse(mBinderService.areBubblesAllowed(PKG)); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 98260318ea9d..e6ac52d2bf6f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -339,8 +339,8 @@ public class ActivityStarterTests extends WindowTestsBase { // Direct starter to use spy stack. doReturn(stack).when(mRootWindowContainer) .getLaunchRootTask(any(), any(), any(), anyBoolean()); - doReturn(stack).when(mRootWindowContainer).getLaunchRootTask(any(), any(), any(), - anyBoolean(), any(), anyInt(), anyInt()); + doReturn(stack).when(mRootWindowContainer).getLaunchRootTask(any(), any(), any(), any(), + anyBoolean(), any(), anyInt(), anyInt(), anyInt()); } // Set up mock package manager internal and make sure no unmocked methods are called @@ -1119,8 +1119,8 @@ public class ActivityStarterTests extends WindowTestsBase { stack.addChild(targetRecord); - doReturn(stack).when(mRootWindowContainer) - .getLaunchRootTask(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt()); + doReturn(stack).when(mRootWindowContainer).getLaunchRootTask(any(), any(), any(), any(), + anyBoolean(), any(), anyInt(), anyInt(), anyInt()); starter.mStartActivity = new ActivityBuilder(mAtm).build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 4dbb2de283f5..e09606e3389f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -54,6 +54,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; +import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE; import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; @@ -1244,7 +1247,6 @@ public class DisplayContentTests extends WindowTestsBase { final DisplayContent displayContent = createNewDisplay(); Mockito.doReturn(mockLogger).when(displayContent).getMetricsLogger(); Mockito.doReturn(oldConfig).doReturn(newConfig).when(displayContent).getConfiguration(); - doNothing().when(displayContent).preOnConfigurationChanged(); displayContent.onConfigurationChanged(newConfig); @@ -1321,6 +1323,8 @@ public class DisplayContentTests extends WindowTestsBase { app.setRequestedOrientation(newOrientation); assertTrue(app.isFixedRotationTransforming()); + assertTrue(mAppWindow.matchesDisplayAreaBounds()); + assertFalse(mAppWindow.isLetterboxedAppWindow()); assertTrue(mDisplayContent.getDisplayRotation().shouldRotateSeamlessly( ROTATION_0 /* oldRotation */, ROTATION_90 /* newRotation */, false /* forceUpdate */)); @@ -1458,54 +1462,51 @@ public class DisplayContentTests extends WindowTestsBase { public void testFixedRotationWithPip() { final DisplayContent displayContent = mDefaultDisplay; unblockDisplayRotation(displayContent); + // Unblock the condition in PinnedTaskController#continueOrientationChangeIfNeeded. + doNothing().when(displayContent).prepareAppTransition(anyInt()); // Make resume-top really update the activity state. - setBooted(mWm.mAtmService); + setBooted(mAtm); + clearInvocations(mWm); // Speed up the test by a few seconds. - mWm.mAtmService.deferWindowLayout(); - doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt()); + mAtm.deferWindowLayout(); - final Configuration displayConfig = displayContent.getConfiguration(); - final ActivityRecord pinnedActivity = createActivityRecord(displayContent, - WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); + final ActivityRecord homeActivity = createActivityRecord( + displayContent.getDefaultTaskDisplayArea().getRootHomeTask()); + final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm).setCreateTask(true).build(); final Task pinnedTask = pinnedActivity.getRootTask(); - final ActivityRecord homeActivity = createActivityRecord(displayContent); - if (displayConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { - homeActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT); - pinnedActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); - } else { - homeActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); - pinnedActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT); - } - final int homeConfigOrientation = homeActivity.getRequestedConfigurationOrientation(); - final int pinnedConfigOrientation = pinnedActivity.getRequestedConfigurationOrientation(); + doReturn((displayContent.getRotation() + 1) % 4).when(displayContent) + .rotationForActivityInDifferentOrientation(eq(homeActivity)); + // Enter PiP from fullscreen. + pinnedTask.setWindowingMode(WINDOWING_MODE_PINNED); - assertEquals(homeConfigOrientation, displayConfig.orientation); + assertTrue(displayContent.hasTopFixedRotationLaunchingApp()); + assertTrue(displayContent.mPinnedTaskController.shouldDeferOrientationChange()); + verify(mWm, never()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt()); + clearInvocations(pinnedTask); + + // Assume that the PiP enter animation is done then the new bounds are set. Expect the + // orientation update is no longer deferred. + displayContent.mPinnedTaskController.setEnterPipBounds(pinnedTask.getBounds()); + // The Task Configuration was frozen to skip the change of orientation. + verify(pinnedTask, never()).onConfigurationChanged(any()); + assertFalse(displayContent.mPinnedTaskController.shouldDeferOrientationChange()); + assertFalse(displayContent.hasTopFixedRotationLaunchingApp()); + assertEquals(homeActivity.getConfiguration().orientation, + displayContent.getConfiguration().orientation); - clearInvocations(mWm); + doReturn((displayContent.getRotation() + 1) % 4).when(displayContent) + .rotationForActivityInDifferentOrientation(eq(pinnedActivity)); // Leave PiP to fullscreen. Simulate the step of PipTaskOrganizer that sets the activity // to fullscreen, so fixed rotation will apply on it. pinnedActivity.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - homeActivity.setState(Task.ActivityState.STOPPED, "test"); - assertTrue(displayContent.hasTopFixedRotationLaunchingApp()); - verify(mWm, never()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt()); - assertNotEquals(pinnedConfigOrientation, displayConfig.orientation); // Assume the animation of PipTaskOrganizer is done and then commit fullscreen to task. pinnedTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); displayContent.continueUpdateOrientationForDiffOrienLaunchingApp(); - assertFalse(displayContent.getPinnedTaskController().isPipActiveOrWindowingModeChanging()); - assertEquals(pinnedConfigOrientation, displayConfig.orientation); - - clearInvocations(mWm); - // Enter PiP from fullscreen. The orientation can be updated from - // ensure-visibility/resume-focused-stack -> ActivityRecord#makeActiveIfNeeded -> resume. - pinnedTask.setWindowingMode(WINDOWING_MODE_PINNED); - - assertFalse(displayContent.hasTopFixedRotationLaunchingApp()); - verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt()); - assertEquals(homeConfigOrientation, displayConfig.orientation); - assertTrue(displayContent.getPinnedTaskController().isPipActiveOrWindowingModeChanging()); + assertFalse(displayContent.mPinnedTaskController.isFreezingTaskConfig(pinnedTask)); + assertEquals(pinnedActivity.getConfiguration().orientation, + displayContent.getConfiguration().orientation); } @Test @@ -1911,6 +1912,32 @@ public class DisplayContentTests extends WindowTestsBase { verify(t).show(mDisplayContent.mImeScreenshot); } + @UseTestDisplay(addWindows = {W_INPUT_METHOD}, addAllCommonWindows = true) + @Test + public void testShowImeScreenshot() { + final Task rootTask = createTask(mDisplayContent); + final Task task = createTaskInRootTask(rootTask, 0 /* userId */); + final ActivityRecord activity = createActivityRecord(mDisplayContent, task); + final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win"); + task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE); + doReturn(true).when(task).okToAnimate(); + ArrayList<WindowContainer> sources = new ArrayList<>(); + sources.add(activity); + + mDisplayContent.setImeLayeringTarget(win); + spyOn(mDisplayContent); + + // Expecting the IME screenshot only be attached when performing task closing transition. + task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */, + false /* isVoiceInteraction */, sources); + verify(mDisplayContent).showImeScreenshot(); + + clearInvocations(mDisplayContent); + activity.applyAnimation(null, TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE, false /* enter */, + false /* isVoiceInteraction */, sources); + verify(mDisplayContent, never()).showImeScreenshot(); + } + @Test public void testRotateBounds_keepSamePhysicalPosition() { final DisplayContent dc = diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java index 2321a73fefb2..e1aca55762d6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -121,8 +121,6 @@ public class DisplayRotationTests { sMockWm = mock(WindowManagerService.class); sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class); sMockWm.mPolicy = mock(WindowManagerPolicy.class); - sMockWm.mConstants = mock(WindowManagerConstants.class); - sMockWm.mConstants.mRawSensorLoggingEnabled = true; } @AfterClass 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 bdc4b4eae630..2c3f52e05add 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java @@ -91,7 +91,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider(); // Display: 1920x1200 (landscape). First and second display are both 860x1200 (portrait). - mDisplay = (DualDisplayContent) new DualDisplayContent.Builder(mAtm, 1920, 1200).build(); + mDisplay = new DualDisplayContent.Builder(mAtm, 1920, 1200).build(); mFirstRoot = mDisplay.mFirstRoot; mSecondRoot = mDisplay.mSecondRoot; mFirstTda = mDisplay.getTaskDisplayArea(FEATURE_FIRST_TASK_CONTAINER); @@ -395,7 +395,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { } /** Display with two {@link DisplayAreaGroup}. Each of them take half of the screen. */ - private static class DualDisplayContent extends TestDisplayContent { + static class DualDisplayContent extends TestDisplayContent { final DisplayAreaGroup mFirstRoot; final DisplayAreaGroup mSecondRoot; final Rect mLastDisplayBounds; @@ -476,11 +476,15 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { TestDisplayContent createInternal(Display display) { return new DualDisplayContent(mService.mRootWindowContainer, display); } + + DualDisplayContent build() { + return (DualDisplayContent) super.build(); + } } } /** Policy to create a dual {@link DisplayAreaGroup} policy in test. */ - private static class DualDisplayTestPolicyProvider implements DisplayAreaPolicy.Provider { + static class DualDisplayTestPolicyProvider implements DisplayAreaPolicy.Provider { @Override public DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content, diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java index 1b9308d32c8c..f2418c68358d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java @@ -47,6 +47,7 @@ import com.android.server.inputmethod.InputMethodMenuController; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; // TODO(b/157888351): Move the test to inputmethod package once we find the way to test the // scenario there. @@ -59,10 +60,15 @@ import org.junit.runner.RunWith; public class InputMethodMenuControllerTest extends WindowTestsBase { private InputMethodMenuController mController; - private TestDisplayContent mSecondaryDisplay; + private DualDisplayAreaGroupPolicyTest.DualDisplayContent mSecondaryDisplay; @Before public void setUp() throws Exception { + // Let the Display to be created with the DualDisplay policy. + final DisplayAreaPolicy.Provider policyProvider = + new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider(); + Mockito.doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider(); + mController = new InputMethodMenuController(mock(InputMethodManagerService.class)); // Mock addWindowTokenWithOptions to create a test window token. @@ -80,7 +86,8 @@ public class InputMethodMenuControllerTest extends WindowTestsBase { }).when(wms).attachWindowContextToDisplayArea(any(), eq(TYPE_INPUT_METHOD_DIALOG), anyInt(), any()); - mSecondaryDisplay = new TestDisplayContent.Builder(mAtm, 1000, 1000).build(); + mSecondaryDisplay = new DualDisplayAreaGroupPolicyTest.DualDisplayContent + .Builder(mAtm, 1000, 1000).build(); // Mock DisplayManagerGlobal to return test display when obtaining Display instance. final int displayId = mSecondaryDisplay.getDisplayId(); @@ -105,6 +112,22 @@ public class InputMethodMenuControllerTest extends WindowTestsBase { assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mSecondaryDisplay); } + @Test + public void testGetSettingsContextOnDualDisplayContent() { + final Context context = mController.getSettingsContext(mSecondaryDisplay.getDisplayId()); + + final DisplayArea.Tokens imeContainer = mSecondaryDisplay.getImeContainer(); + assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay); + + mSecondaryDisplay.mFirstRoot.placeImeContainer(imeContainer); + assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay.mFirstRoot); + assertImeSwitchContextMetricsValidity(context, mSecondaryDisplay); + + mSecondaryDisplay.mSecondRoot.placeImeContainer(imeContainer); + assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay.mSecondRoot); + assertImeSwitchContextMetricsValidity(context, mSecondaryDisplay); + } + private void assertImeSwitchContextMetricsValidity(Context context, DisplayContent dc) { assertThat(context.getDisplayId()).isEqualTo(dc.getDisplayId()); diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java index 37da529d43b7..b6cfa8e96a4c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -177,7 +177,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { mFinishedCallback); mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN); - mClock.fastForward(2500); + mClock.fastForward(10500); mHandler.timeAdvance(); verify(mMockRunner).onAnimationCancelled(); @@ -198,12 +198,12 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { mFinishedCallback); mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN); - mClock.fastForward(2500); + mClock.fastForward(10500); mHandler.timeAdvance(); verify(mMockRunner, never()).onAnimationCancelled(); - mClock.fastForward(10000); + mClock.fastForward(52500); mHandler.timeAdvance(); verify(mMockRunner).onAnimationCancelled(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 0bf237dc6545..4f5511b55d3a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -980,7 +980,8 @@ public class RootWindowContainerTests extends WindowTestsBase { doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId, 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info); final Task result = mRootWindowContainer.getLaunchRootTask(r, options, - null /* task */, true /* onTop */, null, 300 /* test realCallerPid */, + null /* task */, null /* sourceTask */, true /* onTop */, null /* launchParams */, + 0 /* launchFlags */, 300 /* test realCallerPid */, 300 /* test realCallerUid */); // Assert that the root task is returned as expected. diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java index 92d4edec85f4..67b273a5a82d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -28,6 +28,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; @@ -75,6 +76,75 @@ import org.junit.runner.RunWith; public class TaskDisplayAreaTests extends WindowTestsBase { @Test + public void getLaunchRootTask_checksLaunchAdjacentFlagRoot() { + final Task rootTask = createTask( + mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); + rootTask.mCreatedByOrganizer = true; + final Task adjacentRootTask = createTask( + mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); + adjacentRootTask.mCreatedByOrganizer = true; + final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea(); + adjacentRootTask.mAdjacentTask = rootTask; + rootTask.mAdjacentTask = adjacentRootTask; + + taskDisplayArea.setLaunchAdjacentFlagRootTask(adjacentRootTask); + Task actualRootTask = taskDisplayArea.getLaunchRootTask( + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, null /* options */, + null /* sourceTask */, FLAG_ACTIVITY_LAUNCH_ADJACENT); + assertSame(adjacentRootTask, actualRootTask.getRootTask()); + + taskDisplayArea.setLaunchAdjacentFlagRootTask(null); + actualRootTask = taskDisplayArea.getLaunchRootTask(WINDOWING_MODE_UNDEFINED, + ACTIVITY_TYPE_STANDARD, null /* options */, null /* sourceTask */, + FLAG_ACTIVITY_LAUNCH_ADJACENT); + assertNull(actualRootTask); + } + + @Test + public void getLaunchRootTask_checksFocusedRootTask() { + final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); + final Task rootTask = createTaskWithActivity( + taskDisplayArea, + WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, ON_TOP, true); + rootTask.mCreatedByOrganizer = true; + + final Task adjacentRootTask = createTask( + mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); + adjacentRootTask.mCreatedByOrganizer = true; + adjacentRootTask.mAdjacentTask = rootTask; + rootTask.mAdjacentTask = adjacentRootTask; + + taskDisplayArea.setLaunchRootTask(rootTask, + new int[]{WINDOWING_MODE_MULTI_WINDOW}, new int[]{ACTIVITY_TYPE_STANDARD}); + + Task actualRootTask = taskDisplayArea.getLaunchRootTask( + WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, null /* options */, + null /* sourceTask */, 0 /*launchFlags*/); + assertTrue(actualRootTask.isFocusedRootTaskOnDisplay()); + } + + @Test + public void getLaunchRootTask_fromLaunchAdjacentFlagRoot_checksAdjacentRoot() { + final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent); + final Task rootTask = createTask( + mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); + rootTask.mCreatedByOrganizer = true; + final Task adjacentRootTask = createTask( + mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); + adjacentRootTask.mCreatedByOrganizer = true; + final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea(); + adjacentRootTask.mAdjacentTask = rootTask; + rootTask.mAdjacentTask = adjacentRootTask; + + taskDisplayArea.setLaunchAdjacentFlagRootTask(adjacentRootTask); + final Task actualRootTask = taskDisplayArea.getLaunchRootTask( + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, null /* options */, + adjacentRootTask /* sourceTask */, FLAG_ACTIVITY_LAUNCH_ADJACENT); + + assertSame(rootTask, actualRootTask.getRootTask()); + } + + @Test public void getOrCreateLaunchRootRespectsResolvedWindowingMode() { final Task rootTask = createTask( mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); @@ -90,8 +160,8 @@ public class TaskDisplayAreaTests extends WindowTestsBase { launchParams.mWindowingMode = WINDOWING_MODE_FREEFORM; final Task actualRootTask = taskDisplayArea.getOrCreateRootTask( - activity, null /* options */, candidateRootTask, - launchParams, ACTIVITY_TYPE_STANDARD, true /* onTop */); + activity, null /* options */, candidateRootTask, null /* sourceTask */, + launchParams, 0 /* launchFlags */, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertSame(rootTask, actualRootTask.getRootTask()); } @@ -111,8 +181,9 @@ public class TaskDisplayAreaTests extends WindowTestsBase { options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM); final Task actualRootTask = taskDisplayArea.getOrCreateRootTask( - activity, options, candidateRootTask, - null /* launchParams */, ACTIVITY_TYPE_STANDARD, true /* onTop */); + activity, options, candidateRootTask, null /* sourceTask */, + null /* launchParams */, 0 /* launchFlags */, ACTIVITY_TYPE_STANDARD, + true /* onTop */); assertSame(rootTask, actualRootTask.getRootTask()); } @@ -458,8 +529,8 @@ public class TaskDisplayAreaTests extends WindowTestsBase { boolean reuseCandidate) { final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea(); final Task rootTask = taskDisplayArea.getOrCreateRootTask(windowingMode, activityType, - false /* onTop */, null /* intent */, candidateTask /* candidateTask */, - null /* activityOptions */); + false /* onTop */, candidateTask /* candidateTask */, null /* sourceTask */, + null /* activityOptions */, 0 /* launchFlags */); assertEquals(reuseCandidate, rootTask == candidateTask); } 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 2389d2d6e8d6..13ef9982494e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -80,6 +80,7 @@ import android.util.DisplayMetrics; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; import android.util.Xml; +import android.view.Display; import android.view.DisplayInfo; import androidx.test.filters.MediumTest; @@ -1338,6 +1339,16 @@ public class TaskTests extends WindowTestsBase { verify(display).onDescendantOrientationChanged(same(task)); } + @Test + public void testGetNonNullDimmerOnUntrustedDisplays() { + final DisplayInfo untrustedDisplayInfo = new DisplayInfo(mDisplayInfo); + untrustedDisplayInfo.flags &= ~Display.FLAG_TRUSTED; + final DisplayContent untrustedDisplay = createNewDisplay(untrustedDisplayInfo); + final ActivityRecord activity = createActivityRecord(untrustedDisplay); + activity.setOccludesParent(false); + assertNotNull(activity.getTask().getDimmer()); + } + private Task getTestTask() { final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); return task.getBottomMostTask(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index bfbe203fb65e..8d067beff44c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.view.InsetsState.ITYPE_STATUS_BAR; @@ -47,6 +48,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL; import static com.android.server.wm.WindowContainer.SYNC_STATE_WAITING_FOR_DRAW; import static com.google.common.truth.Truth.assertThat; @@ -877,4 +879,30 @@ public class WindowStateTests extends WindowTestsBase { mDisplayContent.getInsetsStateController().notifyInsetsChanged(); verify(app).notifyInsetsChanged(); } + + @UseTestDisplay(addWindows = { W_ACTIVITY }) + @Test + public void testUpdateImeControlTargetWhenLeavingMultiWindow() { + WindowState app = createWindow(null, TYPE_BASE_APPLICATION, + mAppWindow.mToken, "app"); + mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController()); + + spyOn(app); + mDisplayContent.setImeInputTarget(mAppWindow); + mDisplayContent.setImeLayeringTarget(mAppWindow); + + // Simulate entering multi-window mode and verify if the IME control target is remote. + app.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, app.getWindowingMode()); + assertEquals(mDisplayContent.mRemoteInsetsControlTarget, + mDisplayContent.computeImeControlTarget()); + + // Simulate exiting multi-window mode and verify if the IME control target changed + // to the app window. + spyOn(app.getDisplayContent()); + app.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN); + + verify(app.getDisplayContent()).updateImeControlTarget(); + assertEquals(mAppWindow, mDisplayContent.getImeTarget(IME_TARGET_CONTROL).getWindow()); + } } diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java index 6bba65dc36ae..628f8cdc8f0c 100644 --- a/services/translation/java/com/android/server/translation/TranslationManagerService.java +++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java @@ -44,6 +44,7 @@ import android.view.translation.ITranslationManager; import android.view.translation.TranslationContext; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationManager.UiTranslationState; +import android.view.translation.UiTranslationSpec; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; @@ -170,6 +171,28 @@ public final class TranslationManagerService } @Override + public void registerTranslationCapabilityCallback(IRemoteCallback callback, int userId) { + TranslationManagerServiceImpl service; + synchronized (mLock) { + service = getServiceForUserLocked(userId); + } + if (service != null) { + service.registerTranslationCapabilityCallback(callback, Binder.getCallingUid()); + } + } + + @Override + public void unregisterTranslationCapabilityCallback(IRemoteCallback callback, int userId) { + TranslationManagerServiceImpl service; + synchronized (mLock) { + service = getServiceForUserLocked(userId); + } + if (service != null) { + service.unregisterTranslationCapabilityCallback(callback); + } + } + + @Override public void onSessionCreated(TranslationContext translationContext, int sessionId, IResultReceiver receiver, int userId) throws RemoteException { synchronized (mLock) { @@ -187,14 +210,14 @@ public final class TranslationManagerService @Override public void updateUiTranslationState(@UiTranslationState int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, List<AutofillId> viewIds, - IBinder token, int taskId, int userId) { + IBinder token, int taskId, UiTranslationSpec uiTranslationSpec, int userId) { enforceCallerHasPermission(MANAGE_UI_TRANSLATION); synchronized (mLock) { final TranslationManagerServiceImpl service = getServiceForUserLocked(userId); if (service != null && (isDefaultServiceLocked(userId) || isCalledByServiceAppLocked(userId, "updateUiTranslationState"))) { service.updateUiTranslationStateLocked(state, sourceSpec, targetSpec, viewIds, - token, taskId); + token, taskId, uiTranslationSpec); } } } diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java index be9e0ec1a0d4..4198d3b86500 100644 --- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java +++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java @@ -41,6 +41,7 @@ import android.view.translation.TranslationCapability; import android.view.translation.TranslationContext; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationManager.UiTranslationState; +import android.view.translation.UiTranslationSpec; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; @@ -142,6 +143,15 @@ final class TranslationManagerServiceImpl extends } } + public void registerTranslationCapabilityCallback(IRemoteCallback callback, int sourceUid) { + mTranslationCapabilityCallbacks.register(callback, sourceUid); + ensureRemoteServiceLocked(); + } + + public void unregisterTranslationCapabilityCallback(IRemoteCallback callback) { + mTranslationCapabilityCallbacks.unregister(callback); + } + @GuardedBy("mLock") void onSessionCreatedLocked(@NonNull TranslationContext translationContext, int sessionId, IResultReceiver resultReceiver) { @@ -154,7 +164,7 @@ final class TranslationManagerServiceImpl extends @GuardedBy("mLock") public void updateUiTranslationStateLocked(@UiTranslationState int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, List<AutofillId> viewIds, - IBinder token, int taskId) { + IBinder token, int taskId, UiTranslationSpec uiTranslationSpec) { // Get top activity for a given task id final ActivityTokens taskTopActivityTokens = mActivityTaskManagerInternal.getTopActivityForTask(taskId); @@ -165,6 +175,7 @@ final class TranslationManagerServiceImpl extends return; } try { + // TODO: Pipe uiTranslationSpec through to the UiTranslationController. taskTopActivityTokens.getApplicationThread().updateUiTranslationState( taskTopActivityTokens.getActivityToken(), state, sourceSpec, targetSpec, viewIds); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index f7e63757bd77..128602d5acbd 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -943,16 +943,7 @@ public class UsageStatsService extends SystemService implements .APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_FOREGROUND); // check if this activity has already been resumed if (mVisibleActivities.get(event.mInstanceId) != null) break; - final String usageSourcePackage; - switch(mUsageSource) { - case USAGE_SOURCE_CURRENT_ACTIVITY: - usageSourcePackage = event.mPackage; - break; - case USAGE_SOURCE_TASK_ROOT_ACTIVITY: - default: - usageSourcePackage = event.mTaskRootPackage; - break; - } + final String usageSourcePackage = getUsageSourcePackage(event); try { mAppTimeLimit.noteUsageStart(usageSourcePackage, userId); } catch (IllegalArgumentException iae) { @@ -964,26 +955,34 @@ public class UsageStatsService extends SystemService implements mVisibleActivities.put(event.mInstanceId, resumedData); break; case Event.ACTIVITY_PAUSED: - final ActivityData pausedData = mVisibleActivities.get(event.mInstanceId); + ActivityData pausedData = mVisibleActivities.get(event.mInstanceId); if (pausedData == null) { - Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage - + "/" + event.mClass + " event : " + event.mEventType - + " instanceId : " + event.mInstanceId + ")"); - } else { - pausedData.lastEvent = Event.ACTIVITY_PAUSED; - if (event.mTaskRootPackage == null) { - // Task Root info is missing. Repair the event based on previous data - event.mTaskRootPackage = pausedData.mTaskRootPackage; - event.mTaskRootClass = pausedData.mTaskRootClass; + // Must have transitioned from Stopped/Destroyed to Paused state. + final String usageSourcePackage2 = getUsageSourcePackage(event); + try { + mAppTimeLimit.noteUsageStart(usageSourcePackage2, userId); + } catch (IllegalArgumentException iae) { + Slog.e(TAG, "Failed to note usage start", iae); } + pausedData = new ActivityData(event.mTaskRootPackage, event.mTaskRootClass, + usageSourcePackage2); + mVisibleActivities.put(event.mInstanceId, pausedData); + } else { + FrameworkStatsLog.write( + FrameworkStatsLog.APP_USAGE_EVENT_OCCURRED, + uid, + event.mPackage, + event.mClass, + FrameworkStatsLog + .APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_BACKGROUND); + } + + pausedData.lastEvent = Event.ACTIVITY_PAUSED; + if (event.mTaskRootPackage == null) { + // Task Root info is missing. Repair the event based on previous data + event.mTaskRootPackage = pausedData.mTaskRootPackage; + event.mTaskRootClass = pausedData.mTaskRootClass; } - FrameworkStatsLog.write( - FrameworkStatsLog.APP_USAGE_EVENT_OCCURRED, - uid, - event.mPackage, - event.mClass, - FrameworkStatsLog - .APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_BACKGROUND); break; case Event.ACTIVITY_DESTROYED: // Treat activity destroys like activity stops. @@ -993,7 +992,9 @@ public class UsageStatsService extends SystemService implements final ActivityData prevData = mVisibleActivities.removeReturnOld(event.mInstanceId); if (prevData == null) { - // The activity stop was already handled. + Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage + + "/" + event.mClass + " event : " + event.mEventType + + " instanceId : " + event.mInstanceId + ")"); return; } @@ -1059,6 +1060,16 @@ public class UsageStatsService extends SystemService implements } } + private String getUsageSourcePackage(Event event) { + switch(mUsageSource) { + case USAGE_SOURCE_CURRENT_ACTIVITY: + return event.mPackage; + case USAGE_SOURCE_TASK_ROOT_ACTIVITY: + default: + return event.mTaskRootPackage; + } + } + /** * Some events like FLUSH_TO_DISK need to be sent to all userId. * @param event diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index d6ed98f2c3d4..3fbd40f8a060 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -65,7 +65,6 @@ 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; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; @@ -235,19 +234,32 @@ final class HotwordDetectionConnection { Slog.d(TAG, "startListeningFromMic"); } - AudioRecord audioRecord = createMicAudioRecord(audioFormat); - if (audioRecord == null) { - // TODO: Callback.onError(); - return; - } + // TODO: consider making this a non-anonymous class. + IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() { + @Override + public void onDetected(HotwordDetectedResult result) throws RemoteException { + if (DEBUG) { + Slog.d(TAG, "onDetected"); + } + callback.onDetected(result, null, null); + } - handleSoftwareHotwordDetection( - audioFormat, - AudioReader.createFromAudioRecord(audioRecord), - AUDIO_SOURCE_MICROPHONE, - // TODO: handle bundles better. - new PersistableBundle(), - callback); + @Override + public void onRejected(HotwordRejectedResult result) throws RemoteException { + if (DEBUG) { + Slog.d(TAG, "onRejected"); + } + // onRejected isn't allowed here + } + }; + + mRemoteHotwordDetectionService.run( + service -> service.detectFromMicrophoneSource( + null, + AUDIO_SOURCE_MICROPHONE, + null, + null, + internalCallback)); } public void startListeningFromExternalSource( @@ -298,74 +310,12 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "detectFromDspSourceForTest"); } - - AudioRecord record = createFakeAudioRecord(); - if (record == null) { - Slog.d(TAG, "Failed to create fake audio record"); - return; - } - - Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe(); - if (clientPipe == null) { - Slog.d(TAG, "Failed to create pipe"); - return; - } - ParcelFileDescriptor audioSink = clientPipe.second; - ParcelFileDescriptor clientRead = clientPipe.first; - - record.startRecording(); - - mAudioCopyExecutor.execute(() -> { - try (OutputStream fos = - new ParcelFileDescriptor.AutoCloseOutputStream(audioSink)) { - - int remainToRead = 10240; - byte[] buffer = new byte[1024]; - while (remainToRead > 0) { - int bytesRead = record.read(buffer, 0, 1024); - if (DEBUG) { - Slog.d(TAG, "bytesRead = " + bytesRead); - } - if (bytesRead <= 0) { - break; - } - if (bytesRead > 8) { - System.arraycopy(new byte[] {'h', 'o', 't', 'w', 'o', 'r', 'd', '!'}, 0, - buffer, 0, 8); - } - - fos.write(buffer, 0, bytesRead); - remainToRead -= bytesRead; - } - } catch (IOException e) { - Slog.w(TAG, "Failed supplying audio data to validator", e); - } - }); - - Runnable cancellingJob = () -> { - Slog.d(TAG, "Timeout for getting callback from HotwordDetectionService"); - record.stop(); - record.release(); - bestEffortClose(audioSink); - bestEffortClose(clientRead); - }; - - ScheduledFuture<?> cancelingFuture = - mScheduledExecutorService.schedule( - cancellingJob, VALIDATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() { @Override public void onDetected(HotwordDetectedResult result) throws RemoteException { if (DEBUG) { Slog.d(TAG, "onDetected"); } - cancelingFuture.cancel(true); - record.stop(); - record.release(); - bestEffortClose(audioSink); - bestEffortClose(clientRead); - externalCallback.onKeyphraseDetected(recognitionEvent); } @@ -374,19 +324,13 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "onRejected"); } - cancelingFuture.cancel(true); - record.stop(); - record.release(); - bestEffortClose(audioSink); - bestEffortClose(clientRead); - externalCallback.onRejected(result); } }; mRemoteHotwordDetectionService.run( service -> service.detectFromDspSource( - clientRead, + recognitionEvent, recognitionEvent.getCaptureFormat(), VALIDATION_TIMEOUT_MILLIS, internalCallback)); @@ -398,49 +342,6 @@ final class HotwordDetectionConnection { 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(); - bestEffortClose(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 @@ -448,18 +349,6 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "onDetected"); } - bestEffortClose(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); - // TODO: Propagate the HotwordDetectedResult. externalCallback.onKeyphraseDetected(recognitionEvent); } @@ -469,18 +358,16 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "onRejected"); } - cancelingFuture.cancel(true); externalCallback.onRejected(result); } }; mRemoteHotwordDetectionService.run( service -> service.detectFromDspSource( - clientRead, + recognitionEvent, recognitionEvent.getCaptureFormat(), VALIDATION_TIMEOUT_MILLIS, internalCallback)); - bestEffortClose(clientRead); } static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub { diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index d8bd6a576fad..c5fc4365df7a 100755 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -3448,4 +3448,13 @@ public abstract class ConnectionService extends Service { public Handler getHandler() { return mHandler; } + + /** + * Sets this {@link ConnectionService} ready for testing purposes. + * @hide + */ + @VisibleForTesting + public void setReadyForTest() { + mAreAccountsInitialized = true; + } } diff --git a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java index 179248dd2cf9..33b0bbd23086 100644 --- a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java +++ b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java @@ -81,6 +81,15 @@ public class SipMessageParsingUtils { } /** + * @return true if the SIP message start line is considered a response. + */ + public static boolean isSipResponse(String startLine) { + String[] splitLine = splitStartLineAndVerify(startLine); + if (splitLine == null) return false; + return verifySipResponse(splitLine); + } + + /** * Return the via branch parameter, which is used to identify the transaction ID (request and * response pair) in a SIP transaction. * @param headerString The string containing the headers of the SIP message. @@ -140,7 +149,12 @@ public class SipMessageParsingUtils { return !headers.isEmpty() ? headers.get(0).second : null; } - private static String[] splitStartLineAndVerify(String startLine) { + /** + * Validate that the start line is correct and split into its three segments. + * @param startLine The start line to verify and split. + * @return The split start line, which will always have three segments. + */ + public static String[] splitStartLineAndVerify(String startLine) { String[] splitLine = startLine.split(" "); if (isStartLineMalformed(splitLine)) return null; return splitLine; @@ -184,7 +198,7 @@ public class SipMessageParsingUtils { * (This is internally an equalsIgnoreMatch comparison). * @return the matched header keys and values. */ - private static List<Pair<String, String>> parseHeaders(String headerString, + public static List<Pair<String, String>> parseHeaders(String headerString, boolean stopAtFirstMatch, String... matchingHeaderKeys) { // Ensure there is no leading whitespace headerString = removeLeadingWhitespace(headerString); diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index 3b2861600b56..8df41fb6b288 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -183,16 +183,6 @@ public final class PhysicalChannelConfig implements Parcelable { } /** - * @return the absolute radio frequency channel number for this physical channel, - * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown. - * @deprecated Use {@link #getDownlinkChannelNumber()} to get the channel number. - */ - @Deprecated - public int getChannelNumber() { - return getDownlinkChannelNumber(); - } - - /** * @return the rough frequency range for this physical channel, * {@link ServiceState#FREQUENCY_RANGE_UNKNOWN} if unknown. * @see {@link ServiceState#FREQUENCY_RANGE_LOW} diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 08f56132121e..8b6f2b5c8f08 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -1568,16 +1568,6 @@ public class ApnSetting implements Parcelable { } /** - * Same as {@link #getApnTypeString(int)}, but returns "Unknown" instead of an empty string - * when provided with an invalid int for compatibility purposes. - * @hide - */ - public static @NonNull String getApnTypeStringInternal(@ApnType int apnType) { - String result = getApnTypeString(apnType); - return TextUtils.isEmpty(result) ? "Unknown" : result; - } - - /** * Converts the string representation of an APN type to its integer representation. * * @param apnType APN type as a string diff --git a/telephony/java/android/telephony/ims/RcsConfig.java b/telephony/java/android/telephony/ims/RcsConfig.java index d7c3f98fa997..6867c866cd94 100644 --- a/telephony/java/android/telephony/ims/RcsConfig.java +++ b/telephony/java/android/telephony/ims/RcsConfig.java @@ -22,10 +22,10 @@ import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; import android.provider.Telephony.SimInfo; import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; import com.android.telephony.Rlog; @@ -36,7 +36,9 @@ import org.xmlpull.v1.XmlPullParserFactory; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -44,27 +46,138 @@ import java.util.zip.GZIPOutputStream; * RCS config data and methods to process the config * @hide */ -public final class RcsConfig implements Parcelable { +public final class RcsConfig { private static final String LOG_TAG = "RcsConfig"; private static final boolean DBG = Build.IS_ENG; // Tag and attribute defined in RCC.07 A.2 + private static final String TAG_CHARACTERISTIC = "characteristic"; private static final String TAG_PARM = "parm"; + private static final String ATTRIBUTE_TYPE = "type"; private static final String ATTRIBUTE_NAME = "name"; private static final String ATTRIBUTE_VALUE = "value"; // Keyword for Rcs Volte single registration defined in RCC.07 A.1.6.2 private static final String PARM_SINGLE_REGISTRATION = "rcsVolteSingleRegistration"; - private final HashMap<String, String> mValues = new HashMap<>(); + /** + * Characteristic of the RCS provisioning config + */ + public static class Characteristic { + private String mType; + private final Map<String, String> mParms = new ArrayMap<>(); + private final Set<Characteristic> mSubs = new ArraySet<>(); + private final Characteristic mParent; + + private Characteristic(String type, Characteristic parent) { + mType = type; + mParent = parent; + } + + private String getType() { + return mType; + } + + private Map<String, String> getParms() { + return mParms; + } + + private Set<Characteristic> getSubs() { + return mSubs; + } + + private Characteristic getParent() { + return mParent; + } + + private Characteristic getSubByType(String type) { + if (TextUtils.equals(mType, type)) { + return this; + } + Characteristic result = null; + for (Characteristic sub : mSubs) { + result = sub.getSubByType(type); + if (result != null) { + break; + } + } + return result; + } - private RcsConfig(HashMap<String, String> values) { - mValues.putAll(values); + private boolean hasSubByType(String type) { + return getSubByType(type) != null; + } + + private String getParmValue(String name) { + String value = mParms.get(name); + if (value == null) { + for (Characteristic sub : mSubs) { + value = sub.getParmValue(name); + if (value != null) { + break; + } + } + } + return value; + } + + boolean hasParm(String name) { + if (mParms.containsKey(name)) { + return true; + } + + for (Characteristic sub : mSubs) { + if (sub.hasParm(name)) { + return true; + } + } + + return false; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("[" + mType + "]: "); + if (DBG) { + sb.append(mParms); + } + for (Characteristic sub : mSubs) { + sb.append("\n"); + sb.append(sub.toString().replace("\n", "\n\t")); + } + return sb.toString(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Characteristic)) { + return false; + } + + Characteristic o = (Characteristic) obj; + + return TextUtils.equals(mType, o.mType) && mParms.equals(o.mParms) + && mSubs.equals(o.mSubs); + } + + @Override + public int hashCode() { + return Objects.hash(mType, mParms, mSubs); + } } + private final Characteristic mRoot; + private Characteristic mCurrent; + private final byte[] mData; + public RcsConfig(byte[] data) throws IllegalArgumentException { if (data == null || data.length == 0) { throw new IllegalArgumentException("Empty data"); } + mRoot = new Characteristic(null, null); + mCurrent = mRoot; + mData = data; + Characteristic current = mRoot; ByteArrayInputStream inputStream = new ByteArrayInputStream(data); try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); @@ -73,36 +186,51 @@ public final class RcsConfig implements Parcelable { xpp.setInput(inputStream, null); int eventType = xpp.getEventType(); String tag = null; - while (eventType != XmlPullParser.END_DOCUMENT) { + while (eventType != XmlPullParser.END_DOCUMENT && current != null) { if (eventType == XmlPullParser.START_TAG) { tag = xpp.getName().trim().toLowerCase(); - if (tag.equals(TAG_PARM)) { + if (TAG_CHARACTERISTIC.equals(tag)) { + int count = xpp.getAttributeCount(); + String type = null; + if (count > 0) { + for (int i = 0; i < count; i++) { + String name = xpp.getAttributeName(i).trim().toLowerCase(); + if (ATTRIBUTE_TYPE.equals(name)) { + type = xpp.getAttributeValue(xpp.getAttributeNamespace(i), + name).trim().toLowerCase(); + break; + } + } + } + Characteristic next = new Characteristic(type, current); + current.getSubs().add(next); + current = next; + } else if (TAG_PARM.equals(tag)) { int count = xpp.getAttributeCount(); String key = null; String value = null; if (count > 1) { for (int i = 0; i < count; i++) { String name = xpp.getAttributeName(i).trim().toLowerCase(); - if (name.equals(ATTRIBUTE_NAME)) { + if (ATTRIBUTE_NAME.equals(name)) { key = xpp.getAttributeValue(xpp.getAttributeNamespace(i), name).trim().toLowerCase(); - } else if (name.equals(ATTRIBUTE_VALUE)) { + } else if (ATTRIBUTE_VALUE.equals(name)) { value = xpp.getAttributeValue(xpp.getAttributeNamespace(i), name).trim(); } } } if (key != null && value != null) { - mValues.put(key, value); + current.getParms().put(key, value); } } } else if (eventType == XmlPullParser.END_TAG) { - tag = null; - } else if (eventType == XmlPullParser.TEXT) { - String value = xpp.getText().trim(); - if (!TextUtils.isEmpty(tag) && !TextUtils.isEmpty(value)) { - mValues.put(tag, value); + tag = xpp.getName().trim().toLowerCase(); + if (TAG_CHARACTERISTIC.equals(tag)) { + current = current.getParent(); } + tag = null; } eventType = xpp.next(); } @@ -126,8 +254,8 @@ public final class RcsConfig implements Parcelable { * @return Returns the config value if it exists, or defaultVal. */ public @Nullable String getString(@NonNull String tag, @Nullable String defaultVal) { - tag = tag.trim().toLowerCase(); - return mValues.containsKey(tag) ? mValues.get(tag) : defaultVal; + String value = mCurrent.getParmValue(tag.trim().toLowerCase()); + return value != null ? value : defaultVal; } /** @@ -139,9 +267,8 @@ public final class RcsConfig implements Parcelable { * @return Returns the config value if it exists and is a valid int, or defaultVal. */ public int getInteger(@NonNull String tag, int defaultVal) { - tag = tag.trim().toLowerCase(); try { - return Integer.parseInt(mValues.get(tag)); + return Integer.parseInt(getString(tag, null)); } catch (NumberFormatException e) { logd("error to getInteger for " + tag + " due to " + e); } @@ -157,11 +284,8 @@ public final class RcsConfig implements Parcelable { * @return Returns the config value if it exists, or defaultVal. */ public boolean getBoolean(@NonNull String tag, boolean defaultVal) { - tag = tag.trim().toLowerCase(); - if (!mValues.containsKey(tag)) { - return defaultVal; - } - return Boolean.parseBoolean(mValues.get(tag)); + String value = getString(tag, null); + return value != null ? Boolean.parseBoolean(value) : defaultVal; } /** @@ -172,7 +296,62 @@ public final class RcsConfig implements Parcelable { * @return Returns true if it exists, or false. */ public boolean hasConfig(@NonNull String tag) { - return mValues.containsKey(tag.trim().toLowerCase()); + return mCurrent.hasParm(tag.trim().toLowerCase()); + } + + /** + * Return the Characteristic with the given type + */ + public @Nullable Characteristic getCharacteristic(@NonNull String type) { + return mCurrent.getSubByType(type.trim().toLowerCase()); + } + + /** + * Check whether the Characteristic with the given type exists + */ + public boolean hasCharacteristic(@NonNull String type) { + return mCurrent.getSubByType(type.trim().toLowerCase()) != null; + } + + /** + * Set current Characteristic to given Characteristic + */ + public void setCurrentCharacteristic(@NonNull Characteristic current) { + if (current != null) { + mCurrent = current; + } + } + + /** + * Move current Characteristic to parent layer + */ + public boolean moveToParent() { + if (mCurrent.getParent() == null) { + return false; + } + mCurrent = mCurrent.getParent(); + return true; + } + + /** + * Move current Characteristic to the root + */ + public void moveToRoot() { + mCurrent = mRoot; + } + + /** + * Return root Characteristic + */ + public @NonNull Characteristic getRoot() { + return mRoot; + } + + /** + * Return current Characteristic + */ + public @NonNull Characteristic getCurrentCharacteristic() { + return mCurrent; } /** @@ -188,12 +367,10 @@ public final class RcsConfig implements Parcelable { final StringBuilder sb = new StringBuilder(); sb.append("[RCS Config]"); if (DBG) { - mValues.forEach((t, v) -> { - sb.append("\n"); - sb.append(t); - sb.append(" : "); - sb.append(v); - }); + sb.append("=== Root ===\n"); + sb.append(mRoot); + sb.append("=== Current ===\n"); + sb.append(mCurrent); } return sb.toString(); } @@ -206,12 +383,12 @@ public final class RcsConfig implements Parcelable { RcsConfig other = (RcsConfig) obj; - return mValues.equals(other.mValues); + return mRoot.equals(other.mRoot) && mCurrent.equals(other.mCurrent); } @Override public int hashCode() { - return mValues.hashCode(); + return Objects.hash(mRoot, mCurrent); } /** @@ -302,38 +479,6 @@ public final class RcsConfig implements Parcelable { return isCompressed ? data : decompressGzip(data); } - /** - * {@link Parcelable#writeToParcel} - */ - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeMap(mValues); - } - - /** - * {@link Parcelable.Creator} - * - */ - public static final @NonNull Parcelable.Creator<RcsConfig> - CREATOR = new Creator<RcsConfig>() { - @Override - public RcsConfig createFromParcel(Parcel in) { - HashMap<String, String> values = in.readHashMap(null); - return values == null ? null : new RcsConfig(values); - } - - @Override - public RcsConfig[] newArray(int size) { - return new RcsConfig[size]; - } - }; - - /** - * {@link Parcelable#describeContents} - */ - public int describeContents() { - return 0; - } - private static void logd(String msg) { Rlog.d(LOG_TAG, msg); } diff --git a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java index ffbfde65e2d3..08513c23291a 100644 --- a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java +++ b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java @@ -26,6 +26,7 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; +import android.text.TextUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -561,7 +562,12 @@ public final class SipDelegateImsConfiguration implements Parcelable { builder.setSipCniHeader(getString(KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING)); builder.setSipAssociatedUriHeader(getString(KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING)); if (getBoolean(KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL, false)) { - builder.setPublicGruuUri(Uri.parse(getString(KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING))); + String uri = getString(KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING); + Uri gruuUri = null; + if (!TextUtils.isEmpty(uri)) { + gruuUri = Uri.parse(uri); + } + builder.setPublicGruuUri(gruuUri); } if (getBoolean(KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL, false)) { builder.setIpSecConfiguration(new SipDelegateConfiguration.IpSecConfiguration( diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java index ca01d0f664db..a504c9ab1190 100644 --- a/telephony/java/android/telephony/ims/SipDelegateManager.java +++ b/telephony/java/android/telephony/ims/SipDelegateManager.java @@ -34,6 +34,7 @@ import android.telephony.ims.aidl.SipDelegateConnectionAidlWrapper; import android.telephony.ims.stub.DelegateConnectionMessageCallback; import android.telephony.ims.stub.DelegateConnectionStateCallback; import android.telephony.ims.stub.SipDelegate; +import android.util.ArrayMap; import com.android.internal.annotations.VisibleForTesting; @@ -80,13 +81,18 @@ public class SipDelegateManager { public static final int MESSAGE_FAILURE_REASON_DELEGATE_CLOSED = 2; /** - * The SIP message has an invalid start line and the message can not be sent. + * The SIP message has an invalid start line and the message can not be sent or the start line + * failed validation due to the request containing a restricted SIP request method. + * {@link SipDelegateConnection}s can not send SIP requests for the methods: REGISTER, PUBLISH, + * or OPTIONS. */ public static final int MESSAGE_FAILURE_REASON_INVALID_START_LINE = 3; /** * One or more of the header fields in the header section of the outgoing SIP message is invalid - * and the SIP message can not be sent. + * or contains a restricted header value and the SIP message can not be sent. + * {@link SipDelegateConnection}s can not send SIP SUBSCRIBE requests for the "Event" header + * value of "presence". */ public static final int MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS = 4; @@ -163,6 +169,35 @@ public class SipDelegateManager { }) public @interface MessageFailureReason {} + /**@hide*/ + public static final ArrayMap<Integer, String> MESSAGE_FAILURE_REASON_STRING_MAP = + new ArrayMap<>(11); + static { + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_UNKNOWN, + "MESSAGE_FAILURE_REASON_UNKNOWN"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_DELEGATE_DEAD, + "MESSAGE_FAILURE_REASON_DELEGATE_DEAD"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_DELEGATE_CLOSED, + "MESSAGE_FAILURE_REASON_DELEGATE_CLOSED"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS, + "MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT, + "MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG, + "MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG"); + MESSAGE_FAILURE_REASON_STRING_MAP.append( + MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE, + "MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE, + "MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_NOT_REGISTERED, + "MESSAGE_FAILURE_REASON_NOT_REGISTERED"); + MESSAGE_FAILURE_REASON_STRING_MAP.append(MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION, + "MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION"); + MESSAGE_FAILURE_REASON_STRING_MAP.append( + MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION, + "MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION"); + } /** * Access to use this feature tag has been denied for an unknown reason. diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk index bfb5b076237a..dab83046c28f 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk +++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk @@ -89,4 +89,7 @@ LOCAL_JAVA_RESOURCE_FILES := \ $(dynamiccodeloggertest_jar) \ $(dynamiccodeloggertest_executable) \ +LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 +LOCAL_LICENSE_CONDITIONS := notice +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE include $(BUILD_PACKAGE) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt index 9ac504ba3e6f..96c7c0a4ae20 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt @@ -116,7 +116,7 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) } } - @Presubmit + @FlakyTest(bugId = 185400889) @Test open fun noUncoveredRegions() { testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0) @@ -134,7 +134,7 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) testSpec.launcherWindowBecomesVisible() } - @Presubmit + @FlakyTest(bugId = 185400889) @Test open fun launcherLayerReplacesApp() { testSpec.launcherLayerReplacesApp(testApp) diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java index 8be3b7e35d42..c06f8fd44c03 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java @@ -60,7 +60,7 @@ public class ColorFiltersMutateActivity extends Activity { private float mShaderParam1 = 0.0f; static final String sSkSL = - "in shader bitmapShader;\n" + "uniform shader bitmapShader;\n" + "uniform float param1;\n" + "half4 main(float2 xy) {\n" + " return half4(sample(bitmapShader, xy).rgb, param1);\n" diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java index 487c8566ce37..79410cf35f7a 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java @@ -89,7 +89,7 @@ public class RippleActivity extends Activity { + " d = rand(float2(x, y)) > density ? d : d * .2;\n" + " d = d * rand(float2(fraction, x * y));\n" + " float alpha = 1. - pow(fraction, 3.);\n" - + " return float4(sample(in_paintColor).rgb, d * alpha);\n" + + " return float4(sample(in_paintColor, p).rgb, d * alpha);\n" + "}"; RippleView(Context c) { diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java index 912aee686924..ade94a9672bc 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java @@ -440,7 +440,7 @@ public class StretchShaderActivity extends Activity { } } - private static final String SKSL = "in shader uContentTexture;\n" + private static final String SKSL = "uniform shader uContentTexture;\n" + "uniform float uMaxStretchIntensity; // multiplier to apply to scale effect\n" + "uniform float uStretchAffectedDist; // Maximum percentage to stretch beyond bounds" + " of target\n" diff --git a/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt b/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt index 87cfb345e5e0..f23ba26d0039 100644 --- a/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt +++ b/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt @@ -36,15 +36,15 @@ class UnderlyingNetworkInfoTest { @Test fun testParcelUnparcel() { val testInfo = UnderlyingNetworkInfo(TEST_OWNER_UID, TEST_IFACE, TEST_IFACE_LIST) - assertEquals(TEST_OWNER_UID, testInfo.ownerUid) - assertEquals(TEST_IFACE, testInfo.iface) - assertEquals(TEST_IFACE_LIST, testInfo.underlyingIfaces) + assertEquals(TEST_OWNER_UID, testInfo.getOwnerUid()) + assertEquals(TEST_IFACE, testInfo.getInterface()) + assertEquals(TEST_IFACE_LIST, testInfo.getUnderlyingInterfaces()) assertParcelSane(testInfo, 3) val emptyInfo = UnderlyingNetworkInfo(0, String(), listOf()) - assertEquals(0, emptyInfo.ownerUid) - assertEquals(String(), emptyInfo.iface) - assertEquals(listOf(), emptyInfo.underlyingIfaces) + assertEquals(0, emptyInfo.getOwnerUid()) + assertEquals(String(), emptyInfo.getInterface()) + assertEquals(listOf(), emptyInfo.getUnderlyingInterfaces()) assertParcelSane(emptyInfo, 3) } }
\ No newline at end of file diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt index 64b774cc4340..ab6b2f409867 100644 --- a/tests/net/java/android/net/NetworkTemplateTest.kt +++ b/tests/net/java/android/net/NetworkTemplateTest.kt @@ -31,11 +31,16 @@ 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.WIFI_NETWORKID_ALL 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.SUBSCRIBER_ID_MATCH_RULE_EXACT +import android.net.NetworkTemplate.buildTemplateWifi +import android.net.NetworkTemplate.buildTemplateWifiWildcard +import android.net.NetworkTemplate.buildTemplateCarrier import android.net.NetworkTemplate.buildTemplateMobileWithRatType import android.telephony.TelephonyManager import com.android.testutils.assertParcelSane @@ -53,6 +58,7 @@ import kotlin.test.assertTrue private const val TEST_IMSI1 = "imsi1" private const val TEST_IMSI2 = "imsi2" private const val TEST_SSID1 = "ssid1" +private const val TEST_SSID2 = "ssid2" @RunWith(JUnit4::class) class NetworkTemplateTest { @@ -60,8 +66,8 @@ class NetworkTemplateTest { private fun buildMobileNetworkState(subscriberId: String): NetworkStateSnapshot = buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId) - private fun buildWifiNetworkState(ssid: String): NetworkStateSnapshot = - buildNetworkState(TYPE_WIFI, ssid = ssid) + private fun buildWifiNetworkState(subscriberId: String?, ssid: String?): NetworkStateSnapshot = + buildNetworkState(TYPE_WIFI, subscriberId = subscriberId, ssid = ssid) private fun buildNetworkState( type: Int, @@ -94,6 +100,95 @@ class NetworkTemplateTest { } @Test + fun testWifiWildcardMatches() { + val templateWifiWildcard = buildTemplateWifiWildcard() + + val identMobileImsi1 = buildNetworkIdentity(mockContext, + buildMobileNetworkState(TEST_IMSI1), + false, TelephonyManager.NETWORK_TYPE_UMTS) + val identWifiImsiNullSsid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0) + val identWifiImsi1Ssid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0) + + templateWifiWildcard.assertDoesNotMatch(identMobileImsi1) + templateWifiWildcard.assertMatches(identWifiImsiNullSsid1) + templateWifiWildcard.assertMatches(identWifiImsi1Ssid1) + } + + @Test + fun testWifiMatches() { + val templateWifiSsid1 = buildTemplateWifi(TEST_SSID1) + val templateWifiSsid1ImsiNull = buildTemplateWifi(TEST_SSID1, null) + val templateWifiSsid1Imsi1 = buildTemplateWifi(TEST_SSID1, TEST_IMSI1) + val templateWifiSsidAllImsi1 = buildTemplateWifi(WIFI_NETWORKID_ALL, TEST_IMSI1) + + val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1), + false, TelephonyManager.NETWORK_TYPE_UMTS) + val identWifiImsiNullSsid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0) + val identWifiImsi1Ssid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0) + val identWifiImsi2Ssid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_SSID1), true, 0) + val identWifiImsi1Ssid2 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID2), true, 0) + + // Verify that template with SSID only matches any subscriberId and specific SSID. + templateWifiSsid1.assertDoesNotMatch(identMobile1) + templateWifiSsid1.assertMatches(identWifiImsiNullSsid1) + templateWifiSsid1.assertMatches(identWifiImsi1Ssid1) + templateWifiSsid1.assertMatches(identWifiImsi2Ssid1) + templateWifiSsid1.assertDoesNotMatch(identWifiImsi1Ssid2) + + // Verify that template with SSID1 and null imsi matches any network with + // SSID1 and null imsi. + templateWifiSsid1ImsiNull.assertDoesNotMatch(identMobile1) + templateWifiSsid1ImsiNull.assertMatches(identWifiImsiNullSsid1) + templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid1) + templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi2Ssid1) + templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid2) + + // Verify that template with SSID1 and imsi1 matches any network with + // SSID1 and imsi1. + templateWifiSsid1Imsi1.assertDoesNotMatch(identMobile1) + templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsiNullSsid1) + templateWifiSsid1Imsi1.assertMatches(identWifiImsi1Ssid1) + templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi2Ssid1) + templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi1Ssid2) + + // Verify that template with SSID all and imsi1 matches any network with + // any SSID and imsi1. + templateWifiSsidAllImsi1.assertDoesNotMatch(identMobile1) + templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsiNullSsid1) + templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid1) + templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsi2Ssid1) + templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid2) + } + + @Test + fun testCarrierMatches() { + val templateCarrierImsi1 = buildTemplateCarrier(TEST_IMSI1) + + val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1), + false, TelephonyManager.NETWORK_TYPE_UMTS) + val identMobile2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2), + false, TelephonyManager.NETWORK_TYPE_UMTS) + val identWifiSsid1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0) + val identCarrierWifiImsi1 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0) + val identCarrierWifiImsi2 = buildNetworkIdentity( + mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_SSID1), true, 0) + + templateCarrierImsi1.assertMatches(identCarrierWifiImsi1) + templateCarrierImsi1.assertDoesNotMatch(identCarrierWifiImsi2) + templateCarrierImsi1.assertDoesNotMatch(identWifiSsid1) + templateCarrierImsi1.assertMatches(identMobile1) + templateCarrierImsi1.assertDoesNotMatch(identMobile2) + } + + @Test fun testRatTypeGroupMatches() { val stateMobile = buildMobileNetworkState(TEST_IMSI1) // Build UMTS template that matches mobile identities with RAT in the same @@ -117,7 +212,7 @@ class NetworkTemplateTest { val identImsi2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2), false, TelephonyManager.NETWORK_TYPE_UMTS) val identWifi = buildNetworkIdentity( - mockContext, buildWifiNetworkState(TEST_SSID1), true, 0) + mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0) // Assert that identity with the same RAT matches. templateUmts.assertMatches(identUmts) @@ -151,14 +246,16 @@ class NetworkTemplateTest { fun testParcelUnparcel() { val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE, - OEM_MANAGED_ALL) + OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT) val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL, - ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL) + ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT) 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) + ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES, + SUBSCRIBER_ID_MATCH_RULE_EXACT) + assertParcelSane(templateMobile, 10) + assertParcelSane(templateWifi, 10) + assertParcelSane(templateOem, 10) } // Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with @@ -207,15 +304,14 @@ class NetworkTemplateTest { 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 matchSubscriberIds = arrayOf(subscriberId) val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_YES) + OEM_MANAGED_YES, SUBSCRIBER_ID_MATCH_RULE_EXACT) val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL) + OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT) for (identityOemManagedState in oemManagedStates) { val ident = buildNetworkIdentity(mockContext, buildNetworkState(networkType, @@ -226,7 +322,7 @@ class NetworkTemplateTest { for (templateOemManagedState in oemManagedStates) { val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, - NETWORK_TYPE_ALL, templateOemManagedState) + NETWORK_TYPE_ALL, templateOemManagedState, SUBSCRIBER_ID_MATCH_RULE_EXACT) if (identityOemManagedState == templateOemManagedState) { template.assertMatches(ident) } else { diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index dcbfb933f867..f277e94a7bd3 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -44,9 +44,6 @@ import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO; import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE; import static android.net.ConnectivityManager.TYPE_ETHERNET; @@ -57,6 +54,9 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL; import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP; @@ -4273,10 +4273,9 @@ public class ConnectivityServiceTest { waitForIdle(); } - private void setPrivateDnsSettings(String mode, String specifier) { - final ContentResolver cr = mServiceContext.getContentResolver(); - Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_MODE, mode); - Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER, specifier); + private void setPrivateDnsSettings(int mode, String specifier) { + ConnectivitySettingsManager.setPrivateDnsMode(mServiceContext, mode); + ConnectivitySettingsManager.setPrivateDnsHostname(mServiceContext, specifier); mService.updatePrivateDnsSettings(); waitForIdle(); } @@ -5899,9 +5898,9 @@ public class ConnectivityServiceTest { assertEquals("Should have exactly one VPN:", 1, infos.length); UnderlyingNetworkInfo info = infos[0]; assertEquals("Unexpected VPN owner:", (int) vpnUid, info.getOwnerUid()); - assertEquals("Unexpected VPN interface:", vpnIfname, info.getIface()); + assertEquals("Unexpected VPN interface:", vpnIfname, info.getInterface()); assertSameElementsNoDuplicates(underlyingIfaces, - info.getUnderlyingIfaces().toArray(new String[0])); + info.getUnderlyingInterfaces().toArray(new String[0])); } else { assertEquals(0, infos.length); return; @@ -6045,8 +6044,8 @@ public class ConnectivityServiceTest { // network for the VPN... verify(mStatsManager, never()).notifyNetworkStatus(any(List.class), any(List.class), any() /* anyString() doesn't match null */, - argThat(infos -> infos.get(0).getUnderlyingIfaces().size() == 1 - && WIFI_IFNAME.equals(infos.get(0).getUnderlyingIfaces().get(0)))); + argThat(infos -> infos.get(0).getUnderlyingInterfaces().size() == 1 + && WIFI_IFNAME.equals(infos.get(0).getUnderlyingInterfaces().get(0)))); verifyNoMoreInteractions(mStatsManager); reset(mStatsManager); @@ -6060,8 +6059,8 @@ public class ConnectivityServiceTest { waitForIdle(); verify(mStatsManager).notifyNetworkStatus(any(List.class), any(List.class), any() /* anyString() doesn't match null */, - argThat(vpnInfos -> vpnInfos.get(0).getUnderlyingIfaces().size() == 1 - && WIFI_IFNAME.equals(vpnInfos.get(0).getUnderlyingIfaces().get(0)))); + argThat(vpnInfos -> vpnInfos.get(0).getUnderlyingInterfaces().size() == 1 + && WIFI_IFNAME.equals(vpnInfos.get(0).getUnderlyingInterfaces().get(0)))); mEthernetNetworkAgent.disconnect(); waitForIdle(); reset(mStatsManager); diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java index 692c50fbef86..0ffeec98cf90 100644 --- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java @@ -16,10 +16,10 @@ package com.android.server.connectivity; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER; import static android.net.NetworkCapabilities.MAX_TRANSPORT; import static android.net.NetworkCapabilities.MIN_TRANSPORT; @@ -44,6 +44,7 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.Context; +import android.net.ConnectivitySettingsManager; import android.net.IDnsResolver; import android.net.IpPrefix; import android.net.LinkAddress; @@ -187,9 +188,8 @@ public class DnsManagerTest { lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"), TEST_IFACENAME)); - Settings.Global.putString(mContentResolver, - PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); - Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com"); + ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); + ConnectivitySettingsManager.setPrivateDnsHostname(mCtx, "strictmode.com"); mDnsManager.updatePrivateDns(new Network(TEST_NETID), new PrivateDnsConfig("strictmode.com", new InetAddress[] { InetAddress.parseNumericAddress("6.6.6.6"), @@ -294,7 +294,7 @@ public class DnsManagerTest { assertNull(lp.getPrivateDnsServerName()); // Turn private DNS mode off - Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OFF); + ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_OFF); mDnsManager.updatePrivateDns(new Network(TEST_NETID), mDnsManager.getPrivateDnsConfig()); mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); @@ -318,16 +318,15 @@ public class DnsManagerTest { assertEquals(new InetAddress[0], cfgAuto.ips); // Pretend a gservices push sets the default to "off". - Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "off"); + ConnectivitySettingsManager.setPrivateDnsDefaultMode(mCtx, PRIVATE_DNS_MODE_OFF); final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mCtx); assertFalse(cfgOff.useTls); assertEquals("", cfgOff.hostname); assertEquals(new InetAddress[0], cfgOff.ips); // Strict mode still works. - Settings.Global.putString( - mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); - Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com"); + ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); + ConnectivitySettingsManager.setPrivateDnsHostname(mCtx, "strictmode.com"); final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mCtx); assertTrue(cfgStrict.useTls); assertEquals("strictmode.com", cfgStrict.hostname); diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 42441c214575..fd374bc9e68f 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -45,6 +45,7 @@ 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.SUBSCRIBER_ID_MATCH_RULE_EXACT; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateMobileWithRatType; import static android.net.NetworkTemplate.buildTemplateWifi; @@ -669,24 +670,28 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { 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); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID, + SUBSCRIBER_ID_MATCH_RULE_EXACT); 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); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PRIVATE, + SUBSCRIBER_ID_MATCH_RULE_EXACT); 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); + OEM_PAID | OEM_PRIVATE, SUBSCRIBER_ID_MATCH_RULE_EXACT); 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); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES, + SUBSCRIBER_ID_MATCH_RULE_EXACT); 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); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO, + SUBSCRIBER_ID_MATCH_RULE_EXACT); // OEM_PAID network comes online. NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{ diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 0d3fd3fef49c..9410886c3549 100644 --- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -22,7 +22,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.net.NetworkCapabilities; -import android.net.TunnelConnectionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest; import androidx.test.filters.SmallTest; @@ -60,7 +60,7 @@ public class VcnGatewayConnectionConfigTest { }; public static final int MAX_MTU = 1360; - public static final TunnelConnectionParams TUNNEL_CONNECTION_PARAMS = + public static final IkeTunnelConnectionParams TUNNEL_CONNECTION_PARAMS = TunnelConnectionParamsUtilsTest.buildTestParams(); public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-"; @@ -82,7 +82,7 @@ public class VcnGatewayConnectionConfigTest { // Public for use in VcnGatewayConnectionTest public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) { final VcnGatewayConnectionConfig.Builder builder = - newBuilder().setRetryIntervalsMs(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); + newBuilder().setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU); for (int caps : exposedCaps) { builder.addExposedCapability(caps); @@ -134,7 +134,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonNullRetryInterval() { try { - newBuilder().setRetryIntervalsMs(null); + newBuilder().setRetryIntervalsMillis(null); fail("Expected exception due to invalid retryIntervalMs"); } catch (IllegalArgumentException e) { } @@ -143,7 +143,7 @@ public class VcnGatewayConnectionConfigTest { @Test public void testBuilderRequiresNonEmptyRetryInterval() { try { - newBuilder().setRetryIntervalsMs(new long[0]); + newBuilder().setRetryIntervalsMillis(new long[0]); fail("Expected exception due to invalid retryIntervalMs"); } catch (IllegalArgumentException e) { } @@ -174,7 +174,7 @@ public class VcnGatewayConnectionConfigTest { assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams()); - assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs()); + assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis()); assertEquals(MAX_MTU, config.getMaxMtu()); } diff --git a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java index 31561901be9e..582275d0547d 100644 --- a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java +++ b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java @@ -16,6 +16,8 @@ package android.net.vcn; +import static android.net.NetworkCapabilities.REDACT_ALL; +import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; @@ -37,6 +39,12 @@ public class VcnTransportInfoTest { private static final VcnTransportInfo WIFI_UNDERLYING_INFO = new VcnTransportInfo(WIFI_INFO); @Test + public void testRedactionDefaults() { + assertEquals(REDACT_ALL, CELL_UNDERLYING_INFO.getRedaction()); + assertEquals(REDACT_ALL, WIFI_UNDERLYING_INFO.getRedaction()); + } + + @Test public void testGetWifiInfo() { assertEquals(WIFI_INFO, WIFI_UNDERLYING_INFO.getWifiInfo()); @@ -51,6 +59,18 @@ public class VcnTransportInfoTest { } @Test + public void testMakeCopySetsRedactions() { + assertEquals( + REDACT_FOR_NETWORK_SETTINGS, + ((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) + .getRedaction()); + assertEquals( + REDACT_FOR_NETWORK_SETTINGS, + ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(REDACT_FOR_NETWORK_SETTINGS)) + .getRedaction()); + } + + @Test public void testEquals() { assertEquals(CELL_UNDERLYING_INFO, CELL_UNDERLYING_INFO); assertEquals(WIFI_UNDERLYING_INFO, WIFI_UNDERLYING_INFO); @@ -64,8 +84,29 @@ public class VcnTransportInfoTest { } private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) { + // Verify redacted by default Parcel parcel = Parcel.obtain(); vcnTransportInfo.writeToParcel(parcel, 0 /* flags */); + parcel.setDataPosition(0); + assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel)); } + + @Test + public void testParcelUnparcelNotRedactedForSysUi() { + verifyParcelingForSysUi(CELL_UNDERLYING_INFO); + verifyParcelingForSysUi(WIFI_UNDERLYING_INFO); + } + + private void verifyParcelingForSysUi(VcnTransportInfo vcnTransportInfo) { + // Allow fully unredacted; SysUI will have all the relevant permissions. + final VcnTransportInfo unRedacted = (VcnTransportInfo) vcnTransportInfo.makeCopy(0); + final Parcel parcel = Parcel.obtain(); + unRedacted.writeToParcel(parcel, 0 /* flags */); + parcel.setDataPosition(0); + + final VcnTransportInfo unparceled = VcnTransportInfo.CREATOR.createFromParcel(parcel); + assertEquals(vcnTransportInfo, unparceled); + assertEquals(REDACT_ALL, unparceled.getRedaction()); + } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 530e63699e9f..eedaac48293c 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -51,7 +51,6 @@ import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.ipsec.ike.ChildSaProposal; -import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; @@ -181,7 +180,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); final List<ChildSaProposal> saProposals = - ((IkeTunnelConnectionParams) mConfig.getTunnelConnectionParams()) + mConfig.getTunnelConnectionParams() .getTunnelModeChildSessionParams() .getSaProposals(); final int expectedMtu = @@ -344,6 +343,31 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection assertFalse(mGatewayConnection.isInSafeMode()); } + @Test + public void testSubsequentFailedValidationTriggersSafeMode() throws Exception { + triggerChildOpened(); + mTestLooper.dispatchAll(); + + triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); + assertFalse(mGatewayConnection.isInSafeMode()); + + // Trigger a failed validation, and the subsequent safemode timeout. + triggerValidation(NetworkAgent.VALIDATION_STATUS_NOT_VALID); + mTestLooper.dispatchAll(); + + final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mDeps, times(2)) + .newWakeupMessage( + eq(mVcnContext), + any(), + eq(VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM), + runnableCaptor.capture()); + runnableCaptor.getValue().run(); + mTestLooper.dispatchAll(); + + assertTrue(mGatewayConnection.isInSafeMode()); + } + private Consumer<VcnNetworkAgent> setupNetworkAndGetUnwantedCallback() { triggerChildOpened(); mTestLooper.dispatchAll(); diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 044bef5b002f..a88f112f4502 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -38,7 +38,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect public void setUp() throws Exception { super.setUp(); - mFirstRetryInterval = mConfig.getRetryIntervalsMs()[0]; + mFirstRetryInterval = mConfig.getRetryIntervalsMillis()[0]; mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState); diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp index b78f48ce7f17..6364ccdd09e5 100644 --- a/tools/aapt2/Resource.cpp +++ b/tools/aapt2/Resource.cpp @@ -78,6 +78,8 @@ StringPiece to_string(ResourceType type) { return "interpolator"; case ResourceType::kLayout: return "layout"; + case ResourceType::kMacro: + return "macro"; case ResourceType::kMenu: return "menu"; case ResourceType::kMipmap: @@ -119,6 +121,7 @@ static const std::map<StringPiece, ResourceType> sResourceTypeMap{ {"integer", ResourceType::kInteger}, {"interpolator", ResourceType::kInterpolator}, {"layout", ResourceType::kLayout}, + {"macro", ResourceType::kMacro}, {"menu", ResourceType::kMenu}, {"mipmap", ResourceType::kMipmap}, {"navigation", ResourceType::kNavigation}, diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h index cf938703e1e9..307c21d9dc96 100644 --- a/tools/aapt2/Resource.h +++ b/tools/aapt2/Resource.h @@ -57,6 +57,7 @@ enum class ResourceType { kInteger, kInterpolator, kLayout, + kMacro, kMenu, kMipmap, kNavigation, diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 24c60b740bc3..1efabbb46fd5 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -627,6 +627,16 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, } return true; + } else if (resource_type == "macro") { + if (!maybe_name) { + diag_->Error(DiagMessage(out_resource->source) + << "<" << parser->element_name() << "> missing 'name' attribute"); + return false; + } + + out_resource->name.type = ResourceType::kMacro; + out_resource->name.entry = maybe_name.value().to_string(); + return ParseMacro(parser, out_resource); } if (can_be_item) { @@ -726,6 +736,24 @@ bool ResourceParser::ParseItem(xml::XmlPullParser* parser, return true; } +std::optional<FlattenedXmlSubTree> ResourceParser::CreateFlattenSubTree( + xml::XmlPullParser* parser) { + const size_t begin_xml_line = parser->line_number(); + + std::string raw_value; + StyleString style_string; + std::vector<UntranslatableSection> untranslatable_sections; + if (!FlattenXmlSubtree(parser, &raw_value, &style_string, &untranslatable_sections)) { + return {}; + } + + return FlattenedXmlSubTree{.raw_value = raw_value, + .style_string = style_string, + .untranslatable_sections = untranslatable_sections, + .namespace_resolver = parser, + .source = source_.WithLine(begin_xml_line)}; +} + /** * Reads the entire XML subtree and attempts to parse it as some Item, * with typeMask denoting which items it can be. If allowRawValue is @@ -733,42 +761,46 @@ bool ResourceParser::ParseItem(xml::XmlPullParser* parser, * an Item. If allowRawValue is false, nullptr is returned in this * case. */ -std::unique_ptr<Item> ResourceParser::ParseXml(xml::XmlPullParser* parser, - const uint32_t type_mask, +std::unique_ptr<Item> ResourceParser::ParseXml(xml::XmlPullParser* parser, const uint32_t type_mask, const bool allow_raw_value) { - const size_t begin_xml_line = parser->line_number(); - - std::string raw_value; - StyleString style_string; - std::vector<UntranslatableSection> untranslatable_sections; - if (!FlattenXmlSubtree(parser, &raw_value, &style_string, &untranslatable_sections)) { + auto sub_tree = CreateFlattenSubTree(parser); + if (!sub_tree.has_value()) { return {}; } + return ParseXml(sub_tree.value(), type_mask, allow_raw_value, *table_, config_, *diag_); +} - if (!style_string.spans.empty()) { +std::unique_ptr<Item> ResourceParser::ParseXml(const FlattenedXmlSubTree& xmlsub_tree, + const uint32_t type_mask, const bool allow_raw_value, + ResourceTable& table, + const android::ConfigDescription& config, + IDiagnostics& diag) { + if (!xmlsub_tree.style_string.spans.empty()) { // This can only be a StyledString. std::unique_ptr<StyledString> styled_string = - util::make_unique<StyledString>(table_->string_pool.MakeRef( - style_string, StringPool::Context(StringPool::Context::kNormalPriority, config_))); - styled_string->untranslatable_sections = std::move(untranslatable_sections); + util::make_unique<StyledString>(table.string_pool.MakeRef( + xmlsub_tree.style_string, + StringPool::Context(StringPool::Context::kNormalPriority, config))); + styled_string->untranslatable_sections = xmlsub_tree.untranslatable_sections; return std::move(styled_string); } auto on_create_reference = [&](const ResourceName& name) { // name.package can be empty here, as it will assume the package name of the // table. - std::unique_ptr<Id> id = util::make_unique<Id>(); - id->SetSource(source_.WithLine(begin_xml_line)); - table_->AddResource(NewResourceBuilder(name).SetValue(std::move(id)).Build(), diag_); + auto id = util::make_unique<Id>(); + id->SetSource(xmlsub_tree.source); + return table.AddResource(NewResourceBuilder(name).SetValue(std::move(id)).Build(), &diag); }; // Process the raw value. - std::unique_ptr<Item> processed_item = - ResourceUtils::TryParseItemForAttribute(raw_value, type_mask, on_create_reference); + std::unique_ptr<Item> processed_item = ResourceUtils::TryParseItemForAttribute( + xmlsub_tree.raw_value, type_mask, on_create_reference); if (processed_item) { // Fix up the reference. - if (Reference* ref = ValueCast<Reference>(processed_item.get())) { - ResolvePackage(parser, ref); + if (auto ref = ValueCast<Reference>(processed_item.get())) { + ref->allow_raw = allow_raw_value; + ResolvePackage(xmlsub_tree.namespace_resolver, ref); } return processed_item; } @@ -777,17 +809,16 @@ std::unique_ptr<Item> ResourceParser::ParseXml(xml::XmlPullParser* parser, if (type_mask & android::ResTable_map::TYPE_STRING) { // Use the trimmed, escaped string. std::unique_ptr<String> string = util::make_unique<String>( - table_->string_pool.MakeRef(style_string.str, StringPool::Context(config_))); - string->untranslatable_sections = std::move(untranslatable_sections); + table.string_pool.MakeRef(xmlsub_tree.style_string.str, StringPool::Context(config))); + string->untranslatable_sections = xmlsub_tree.untranslatable_sections; return std::move(string); } if (allow_raw_value) { // We can't parse this so return a RawString if we are allowed. - return util::make_unique<RawString>( - table_->string_pool.MakeRef(util::TrimWhitespace(raw_value), - StringPool::Context(config_))); - } else if (util::TrimWhitespace(raw_value).empty()) { + return util::make_unique<RawString>(table.string_pool.MakeRef( + util::TrimWhitespace(xmlsub_tree.raw_value), StringPool::Context(config))); + } else if (util::TrimWhitespace(xmlsub_tree.raw_value).empty()) { // If the text is empty, and the value is not allowed to be a string, encode it as a @null. return ResourceUtils::MakeNull(); } @@ -850,6 +881,35 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser, return true; } +bool ResourceParser::ParseMacro(xml::XmlPullParser* parser, ParsedResource* out_resource) { + auto sub_tree = CreateFlattenSubTree(parser); + if (!sub_tree) { + return false; + } + + if (out_resource->config != ConfigDescription::DefaultConfig()) { + diag_->Error(DiagMessage(out_resource->source) + << "<macro> tags cannot be declared in configurations other than the default " + "configuration'"); + return false; + } + + auto macro = std::make_unique<Macro>(); + macro->raw_value = std::move(sub_tree->raw_value); + macro->style_string = std::move(sub_tree->style_string); + macro->untranslatable_sections = std::move(sub_tree->untranslatable_sections); + + for (const auto& decl : parser->package_decls()) { + macro->alias_namespaces.emplace_back( + Macro::Namespace{.alias = decl.prefix, + .package_name = decl.package.package, + .is_private = decl.package.private_namespace}); + } + + out_resource->value = std::move(macro); + return true; +} + bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out_resource) { if (options_.visibility) { diag_->Error(DiagMessage(out_resource->source) diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h index af0db8c0ba2c..5c92def50616 100644 --- a/tools/aapt2/ResourceParser.h +++ b/tools/aapt2/ResourceParser.h @@ -57,6 +57,14 @@ struct ResourceParserOptions { Maybe<Visibility::Level> visibility; }; +struct FlattenedXmlSubTree { + std::string raw_value; + StyleString style_string; + std::vector<UntranslatableSection> untranslatable_sections; + xml::IPackageDeclStack* namespace_resolver; + Source source; +}; + /* * Parses an XML file for resources and adds them to a ResourceTable. */ @@ -67,9 +75,16 @@ class ResourceParser { const ResourceParserOptions& options = {}); bool Parse(xml::XmlPullParser* parser); + static std::unique_ptr<Item> ParseXml(const FlattenedXmlSubTree& xmlsub_tree, uint32_t type_mask, + bool allow_raw_value, ResourceTable& table, + const android::ConfigDescription& config, + IDiagnostics& diag); + private: DISALLOW_COPY_AND_ASSIGN(ResourceParser); + std::optional<FlattenedXmlSubTree> CreateFlattenSubTree(xml::XmlPullParser* parser); + // Parses the XML subtree as a StyleString (flattened XML representation for strings with // formatting). If parsing fails, false is returned and the out parameters are left in an // unspecified state. Otherwise, @@ -96,7 +111,7 @@ class ResourceParser { bool ParseItem(xml::XmlPullParser* parser, ParsedResource* out_resource, uint32_t format); bool ParseString(xml::XmlPullParser* parser, ParsedResource* out_resource); - + bool ParseMacro(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParsePublic(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseStagingPublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource); @@ -108,8 +123,7 @@ class ResourceParser { bool ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, bool weak); Maybe<Attribute::Symbol> ParseEnumOrFlagItem(xml::XmlPullParser* parser, const android::StringPiece& tag); - bool ParseStyle(const ResourceType type, xml::XmlPullParser* parser, - ParsedResource* out_resource); + bool ParseStyle(ResourceType type, xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseStyleItem(xml::XmlPullParser* parser, Style* style); bool ParseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseArray(xml::XmlPullParser* parser, ParsedResource* out_resource); diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 4a509be56776..279ebcba2f71 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -336,6 +336,90 @@ TEST_F(ResourceParserTest, ParseAttr) { EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_ANY)); } +TEST_F(ResourceParserTest, ParseMacro) { + std::string input = R"(<macro name="foo">12345</macro>)"; + ASSERT_TRUE(TestParse(input)); + + Macro* macro = test::GetValue<Macro>(&table_, "macro/foo"); + ASSERT_THAT(macro, NotNull()); + EXPECT_THAT(macro->raw_value, Eq("12345")); + EXPECT_THAT(macro->style_string.str, Eq("12345")); + EXPECT_THAT(macro->style_string.spans, IsEmpty()); + EXPECT_THAT(macro->untranslatable_sections, IsEmpty()); + EXPECT_THAT(macro->alias_namespaces, IsEmpty()); +} + +TEST_F(ResourceParserTest, ParseMacroUntranslatableSection) { + std::string input = R"(<macro name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +This being <b><xliff:g>human</xliff:g></b> is a guest house.</macro>)"; + ASSERT_TRUE(TestParse(input)); + + Macro* macro = test::GetValue<Macro>(&table_, "macro/foo"); + ASSERT_THAT(macro, NotNull()); + EXPECT_THAT(macro->raw_value, Eq("\nThis being human is a guest house.")); + EXPECT_THAT(macro->style_string.str, Eq(" This being human is a guest house.")); + EXPECT_THAT(macro->style_string.spans.size(), Eq(1)); + EXPECT_THAT(macro->style_string.spans[0].name, Eq("b")); + EXPECT_THAT(macro->style_string.spans[0].first_char, Eq(12)); + EXPECT_THAT(macro->style_string.spans[0].last_char, Eq(16)); + ASSERT_THAT(macro->untranslatable_sections.size(), Eq(1)); + EXPECT_THAT(macro->untranslatable_sections[0].start, Eq(12)); + EXPECT_THAT(macro->untranslatable_sections[0].end, Eq(17)); + EXPECT_THAT(macro->alias_namespaces, IsEmpty()); +} + +TEST_F(ResourceParserTest, ParseMacroNamespaces) { + std::string input = R"(<macro name="foo" xmlns:app="http://schemas.android.com/apk/res/android"> +@app:string/foo</macro>)"; + ASSERT_TRUE(TestParse(input)); + + Macro* macro = test::GetValue<Macro>(&table_, "macro/foo"); + ASSERT_THAT(macro, NotNull()); + EXPECT_THAT(macro->raw_value, Eq("\n@app:string/foo")); + EXPECT_THAT(macro->style_string.str, Eq("@app:string/foo")); + EXPECT_THAT(macro->style_string.spans, IsEmpty()); + EXPECT_THAT(macro->untranslatable_sections, IsEmpty()); + EXPECT_THAT(macro->alias_namespaces.size(), Eq(1)); + EXPECT_THAT(macro->alias_namespaces[0].alias, Eq("app")); + EXPECT_THAT(macro->alias_namespaces[0].package_name, Eq("android")); + EXPECT_THAT(macro->alias_namespaces[0].is_private, Eq(false)); +} + +TEST_F(ResourceParserTest, ParseMacroReference) { + std::string input = R"(<string name="res_string">@macro/foo</string>)"; + ASSERT_TRUE(TestParse(input)); + + Reference* macro = test::GetValue<Reference>(&table_, "string/res_string"); + ASSERT_THAT(macro, NotNull()); + EXPECT_THAT(macro->type_flags, Eq(ResTable_map::TYPE_STRING)); + EXPECT_THAT(macro->allow_raw, Eq(false)); + + input = R"(<style name="foo"> + <item name="bar">@macro/foo</item> + </style>)"; + + ASSERT_TRUE(TestParse(input)); + Style* style = test::GetValue<Style>(&table_, "style/foo"); + ASSERT_THAT(style, NotNull()); + EXPECT_THAT(style->entries.size(), Eq(1)); + + macro = ValueCast<Reference>(style->entries[0].value.get()); + ASSERT_THAT(macro, NotNull()); + EXPECT_THAT(macro->type_flags, Eq(0U)); + EXPECT_THAT(macro->allow_raw, Eq(true)); +} + +TEST_F(ResourceParserTest, ParseMacroNoNameFail) { + std::string input = R"(<macro>12345</macro>)"; + ASSERT_FALSE(TestParse(input)); +} + +TEST_F(ResourceParserTest, ParseMacroNonDefaultConfigurationFail) { + const ConfigDescription watch_config = test::ParseConfigOrDie("watch"); + std::string input = R"(<macro name="foo">12345</macro>)"; + ASSERT_FALSE(TestParse(input, watch_config)); +} + // Old AAPT allowed attributes to be defined under different configurations, but ultimately // stored them with the default configuration. Check that we have the same behavior. TEST_F(ResourceParserTest, ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) { diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp index 5b43df6f0935..e0e80ac02dea 100644 --- a/tools/aapt2/ResourceUtils.cpp +++ b/tools/aapt2/ResourceUtils.cpp @@ -628,7 +628,7 @@ uint32_t AndroidTypeToAttributeTypeMask(uint16_t type) { std::unique_ptr<Item> TryParseItemForAttribute( const StringPiece& value, uint32_t type_mask, - const std::function<void(const ResourceName&)>& on_create_reference) { + const std::function<bool(const ResourceName&)>& on_create_reference) { using android::ResTable_map; auto null_or_empty = TryParseNullOrEmpty(value); @@ -639,8 +639,11 @@ std::unique_ptr<Item> TryParseItemForAttribute( bool create = false; auto reference = TryParseReference(value, &create); if (reference) { + reference->type_flags = type_mask; if (create && on_create_reference) { - on_create_reference(reference->name.value()); + if (!on_create_reference(reference->name.value())) { + return {}; + } } return std::move(reference); } @@ -689,7 +692,7 @@ std::unique_ptr<Item> TryParseItemForAttribute( */ std::unique_ptr<Item> TryParseItemForAttribute( const StringPiece& str, const Attribute* attr, - const std::function<void(const ResourceName&)>& on_create_reference) { + const std::function<bool(const ResourceName&)>& on_create_reference) { using android::ResTable_map; const uint32_t type_mask = attr->type_mask; diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h index f77766ee9061..be493db8cee0 100644 --- a/tools/aapt2/ResourceUtils.h +++ b/tools/aapt2/ResourceUtils.h @@ -204,11 +204,11 @@ std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* enum_attr, */ std::unique_ptr<Item> TryParseItemForAttribute( const android::StringPiece& value, const Attribute* attr, - const std::function<void(const ResourceName&)>& on_create_reference = {}); + const std::function<bool(const ResourceName&)>& on_create_reference = {}); std::unique_ptr<Item> TryParseItemForAttribute( const android::StringPiece& value, uint32_t type_mask, - const std::function<void(const ResourceName&)>& on_create_reference = {}); + const std::function<bool(const ResourceName&)>& on_create_reference = {}); uint32_t AndroidTypeToAttributeTypeMask(uint16_t type); diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp index 574bd2e44a84..2a90f267f185 100644 --- a/tools/aapt2/ResourceValues.cpp +++ b/tools/aapt2/ResourceValues.cpp @@ -111,12 +111,15 @@ bool Reference::Equals(const Value* value) const { if (!other) { return false; } - return reference_type == other->reference_type && - private_reference == other->private_reference && id == other->id && - name == other->name; + return reference_type == other->reference_type && private_reference == other->private_reference && + id == other->id && name == other->name && type_flags == other->type_flags; } bool Reference::Flatten(android::Res_value* out_value) const { + if (name && name.value().type == ResourceType::kMacro) { + return false; + } + const ResourceId resid = id.value_or_default(ResourceId(0)); const bool dynamic = resid.is_valid() && is_dynamic; @@ -551,7 +554,7 @@ bool Attribute::IsCompatibleWith(const Attribute& attr) const { return this_type_mask == that_type_mask; } -std::string Attribute::MaskString() const { +std::string Attribute::MaskString(uint32_t type_mask) { if (type_mask == android::ResTable_map::TYPE_ANY) { return "any"; } @@ -650,6 +653,10 @@ std::string Attribute::MaskString() const { return out.str(); } +std::string Attribute::MaskString() const { + return MaskString(type_mask); +} + void Attribute::Print(std::ostream* out) const { *out << "(attr) " << MaskString(); @@ -1017,6 +1024,21 @@ void Styleable::Print(std::ostream* out) const { << " [" << util::Joiner(entries, ", ") << "]"; } +bool Macro::Equals(const Value* value) const { + const Macro* other = ValueCast<Macro>(value); + if (!other) { + return false; + } + return other->raw_value == raw_value && other->style_string.spans == style_string.spans && + other->style_string.str == style_string.str && + other->untranslatable_sections == untranslatable_sections && + other->alias_namespaces == alias_namespaces; +} + +void Macro::Print(std::ostream* out) const { + *out << "(macro) "; +} + bool operator<(const Reference& a, const Reference& b) { int cmp = a.name.value_or_default({}).compare(b.name.value_or_default({})); if (cmp != 0) return cmp < 0; @@ -1149,4 +1171,9 @@ std::unique_ptr<Styleable> CloningValueTransformer::TransformDerived(const Style return CopyValueFields(std::move(new_value), value); } +std::unique_ptr<Macro> CloningValueTransformer::TransformDerived(const Macro* value) { + auto new_value = std::make_unique<Macro>(*value); + return CopyValueFields(std::move(new_value), value); +} + } // namespace aapt diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h index 025864d385cf..d11b013f14d5 100644 --- a/tools/aapt2/ResourceValues.h +++ b/tools/aapt2/ResourceValues.h @@ -164,6 +164,8 @@ struct Reference : public TransformableItem<Reference, BaseItem<Reference>> { Reference::Type reference_type; bool private_reference = false; bool is_dynamic = false; + std::optional<uint32_t> type_flags; + bool allow_raw; Reference(); explicit Reference(const ResourceNameRef& n, Type type = Type::kResource); @@ -311,6 +313,8 @@ struct Attribute : public TransformableValue<Attribute, BaseValue<Attribute>> { bool IsCompatibleWith(const Attribute& attr) const; std::string MaskString() const; + static std::string MaskString(uint32_t type_mask); + void Print(std::ostream* out) const override; bool Matches(const Item& item, DiagMessage* out_msg = nullptr) const; }; @@ -362,6 +366,28 @@ struct Styleable : public TransformableValue<Styleable, BaseValue<Styleable>> { void MergeWith(Styleable* styleable); }; +struct Macro : public TransformableValue<Macro, BaseValue<Macro>> { + std::string raw_value; + StyleString style_string; + std::vector<UntranslatableSection> untranslatable_sections; + + struct Namespace { + std::string alias; + std::string package_name; + bool is_private; + + bool operator==(const Namespace& right) const { + return alias == right.alias && package_name == right.package_name && + is_private == right.is_private; + } + }; + + std::vector<Namespace> alias_namespaces; + + bool Equals(const Value* value) const override; + void Print(std::ostream* out) const override; +}; + template <typename T> typename std::enable_if<std::is_base_of<Value, T>::value, std::ostream&>::type operator<<( std::ostream& out, const std::unique_ptr<T>& value) { @@ -388,6 +414,7 @@ struct CloningValueTransformer : public ValueTransformer { std::unique_ptr<Array> TransformDerived(const Array* value) override; std::unique_ptr<Plural> TransformDerived(const Plural* value) override; std::unique_ptr<Styleable> TransformDerived(const Styleable* value) override; + std::unique_ptr<Macro> TransformDerived(const Macro* value) override; }; } // namespace aapt diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index 4247ec5a3495..b45c0401d19a 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -273,6 +273,7 @@ message CompoundValue { Styleable styleable = 3; Array array = 4; Plural plural = 5; + MacroBody macro = 6; } } @@ -304,6 +305,13 @@ message Reference { // Whether this reference is dynamic. Boolean is_dynamic = 5; + + // The type flags used when compiling the reference. Used for substituting the contents of macros. + uint32 type_flags = 6; + + // Whether raw string values would have been accepted in place of this reference definition. Used + // for substituting the contents of macros. + bool allow_raw = 7; } // A value that represents an ID. This is just a placeholder, as ID values are used to occupy a @@ -591,3 +599,32 @@ message XmlAttribute { // The optional interpreted/compiled version of the `value` string. Item compiled_item = 6; } + +message MacroBody { + string raw_string = 1; + StyleString style_string = 2; + repeated UntranslatableSection untranslatable_sections = 3; + repeated NamespaceAlias namespace_stack = 4; + SourcePosition source = 5; +} + +message NamespaceAlias { + string prefix = 1; + string package_name = 2; + bool is_private = 3; +} + +message StyleString { + message Span { + string name = 1; + uint32 start_index = 2; + uint32 end_index = 3; + } + string str = 1; + repeated Span spans = 2; +} + +message UntranslatableSection { + uint64 start_index = 1; + uint64 end_index = 2; +}
\ No newline at end of file diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h index 1006ca970dc5..3457e0b41859 100644 --- a/tools/aapt2/StringPool.h +++ b/tools/aapt2/StringPool.h @@ -36,6 +36,10 @@ struct Span { std::string name; uint32_t first_char; uint32_t last_char; + + bool operator==(const Span& right) const { + return name == right.name && first_char == right.first_char && last_char == right.last_char; + } }; struct StyleString { diff --git a/tools/aapt2/ValueTransformer.cpp b/tools/aapt2/ValueTransformer.cpp index 6eb2e30fb923..2d7996b9d880 100644 --- a/tools/aapt2/ValueTransformer.cpp +++ b/tools/aapt2/ValueTransformer.cpp @@ -46,5 +46,6 @@ VALUE_CREATE_VALUE_DECL(Style); VALUE_CREATE_VALUE_DECL(Array); VALUE_CREATE_VALUE_DECL(Plural); VALUE_CREATE_VALUE_DECL(Styleable); +VALUE_CREATE_VALUE_DECL(Macro); } // namespace aapt
\ No newline at end of file diff --git a/tools/aapt2/ValueTransformer.h b/tools/aapt2/ValueTransformer.h index 692511132012..6fc4a191b04b 100644 --- a/tools/aapt2/ValueTransformer.h +++ b/tools/aapt2/ValueTransformer.h @@ -37,6 +37,7 @@ struct Style; struct Array; struct Plural; struct Styleable; +struct Macro; #define AAPT_TRANSFORM_VALUE(T) \ virtual std::unique_ptr<T> TransformDerived(const T* value) = 0; \ @@ -97,6 +98,7 @@ struct ValueTransformer { AAPT_TRANSFORM_VALUE(Array); AAPT_TRANSFORM_VALUE(Plural); AAPT_TRANSFORM_VALUE(Styleable); + AAPT_TRANSFORM_VALUE(Macro); protected: StringPool* const pool_; diff --git a/tools/aapt2/ValueVisitor.h b/tools/aapt2/ValueVisitor.h index 4e74ec366dab..d0c9d89b6f0c 100644 --- a/tools/aapt2/ValueVisitor.h +++ b/tools/aapt2/ValueVisitor.h @@ -43,6 +43,9 @@ class ValueVisitor { virtual void Visit(Array* value) { VisitAny(value); } virtual void Visit(Plural* value) { VisitAny(value); } virtual void Visit(Styleable* value) { VisitAny(value); } + virtual void Visit(Macro* value) { + VisitAny(value); + } }; // Const version of ValueVisitor. @@ -92,6 +95,9 @@ class ConstValueVisitor { virtual void Visit(const Styleable* value) { VisitAny(value); } + virtual void Visit(const Macro* value) { + VisitAny(value); + } }; // NOLINT, do not add parentheses around T. diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 2c57fb2b003e..e4d0f3b6bd23 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -462,7 +462,7 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer // that existing projects have out-of-date references which pass compilation. xml::StripAndroidStudioAttributes(doc->root.get()); - XmlReferenceLinker xml_linker; + XmlReferenceLinker xml_linker(table); if (!options_.do_not_fail_on_missing_resources && !xml_linker.Consume(context_, doc)) { return {}; } @@ -2112,7 +2112,7 @@ class Linker { std::unique_ptr<xml::XmlResource> split_manifest = GenerateSplitManifest(app_info_, *split_constraints_iter); - XmlReferenceLinker linker; + XmlReferenceLinker linker(&final_table_); if (!linker.Consume(context_, split_manifest.get())) { context_->GetDiagnostics()->Error(DiagMessage() << "failed to create Split AndroidManifest.xml"); @@ -2143,7 +2143,7 @@ class Linker { // So we give it a package name so it can see local resources. manifest_xml->file.name.package = context_->GetCompilationPackage(); - XmlReferenceLinker manifest_linker; + XmlReferenceLinker manifest_linker(&final_table_); if (options_.merge_only || manifest_linker.Consume(context_, manifest_xml.get())) { if (options_.generate_proguard_rules_path && !proguard::CollectProguardRulesForManifest(manifest_xml.get(), &proguard_keep_set)) { diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp index d1e6d3922f3f..3118eb8f7731 100644 --- a/tools/aapt2/cmd/Link_test.cpp +++ b/tools/aapt2/cmd/Link_test.cpp @@ -24,6 +24,7 @@ using testing::Eq; using testing::HasSubstr; +using testing::IsNull; using testing::Ne; using testing::NotNull; @@ -532,4 +533,109 @@ TEST_F(LinkTest, StagedAndroidApi) { EXPECT_THAT(*result, Eq(0x01fd0072)); } +TEST_F(LinkTest, MacroSubstitution) { + StdErrDiagnostics diag; + const std::string values = + R"(<resources xmlns:an="http://schemas.android.com/apk/res/android"> + <macro name="is_enabled">true</macro> + <macro name="deep_is_enabled">@macro/is_enabled</macro> + <macro name="attr_ref">?is_enabled_attr</macro> + <macro name="raw_string">Hello World!</macro> + <macro name="android_ref">@an:color/primary_text_dark</macro> + + <attr name="is_enabled_attr" /> + <public type="attr" name="is_enabled_attr" id="0x7f010000"/> + + <string name="is_enabled_str">@macro/is_enabled</string> + <bool name="is_enabled_bool">@macro/deep_is_enabled</bool> + + <array name="my_array"> + <item>@macro/is_enabled</item> + </array> + + <style name="MyStyle"> + <item name="android:background">@macro/attr_ref</item> + <item name="android:fontFamily">@macro/raw_string</item> + </style> + </resources>)"; + + const std::string xml_values = + R"(<SomeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:background="@macro/android_ref" + android:fontFamily="@macro/raw_string"> + </SomeLayout>)"; + + // Build a library with a public attribute + const std::string lib_res = GetTestPath("test-res"); + ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), values, lib_res, &diag)); + ASSERT_TRUE(CompileFile(GetTestPath("res/layout/layout.xml"), xml_values, lib_res, &diag)); + + const std::string lib_apk = GetTestPath("test.apk"); + // clang-format off + auto lib_link_args = LinkCommandBuilder(this) + .SetManifestFile(ManifestBuilder(this).SetPackageName("com.test").Build()) + .AddCompiledResDir(lib_res, &diag) + .AddFlag("--no-auto-version") + .Build(lib_apk); + // clang-format on + ASSERT_TRUE(Link(lib_link_args, &diag)); + + auto apk = LoadedApk::LoadApkFromPath(lib_apk, &diag); + ASSERT_THAT(apk, NotNull()); + + // Test that the type flags determines the value type + auto actual_bool = + test::GetValue<BinaryPrimitive>(apk->GetResourceTable(), "com.test:bool/is_enabled_bool"); + ASSERT_THAT(actual_bool, NotNull()); + EXPECT_EQ(android::Res_value::TYPE_INT_BOOLEAN, actual_bool->value.dataType); + EXPECT_EQ(0xffffffffu, actual_bool->value.data); + + auto actual_str = + test::GetValue<String>(apk->GetResourceTable(), "com.test:string/is_enabled_str"); + ASSERT_THAT(actual_str, NotNull()); + EXPECT_EQ(*actual_str->value, "true"); + + // Test nested data structures + auto actual_array = test::GetValue<Array>(apk->GetResourceTable(), "com.test:array/my_array"); + ASSERT_THAT(actual_array, NotNull()); + EXPECT_THAT(actual_array->elements.size(), Eq(1)); + + auto array_el_ref = ValueCast<BinaryPrimitive>(actual_array->elements[0].get()); + ASSERT_THAT(array_el_ref, NotNull()); + EXPECT_THAT(array_el_ref->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN)); + EXPECT_THAT(array_el_ref->value.data, Eq(0xffffffffu)); + + auto actual_style = test::GetValue<Style>(apk->GetResourceTable(), "com.test:style/MyStyle"); + ASSERT_THAT(actual_style, NotNull()); + EXPECT_THAT(actual_style->entries.size(), Eq(2)); + + { + auto style_el = ValueCast<Reference>(actual_style->entries[0].value.get()); + ASSERT_THAT(style_el, NotNull()); + EXPECT_THAT(style_el->reference_type, Eq(Reference::Type::kAttribute)); + EXPECT_THAT(style_el->id, Eq(0x7f010000)); + } + + { + auto style_el = ValueCast<String>(actual_style->entries[1].value.get()); + ASSERT_THAT(style_el, NotNull()); + EXPECT_THAT(*style_el->value, Eq("Hello World!")); + } + + // Test substitution in compiled xml files + auto xml = apk->LoadXml("res/layout/layout.xml", &diag); + ASSERT_THAT(xml, NotNull()); + + auto& xml_attrs = xml->root->attributes; + ASSERT_THAT(xml_attrs.size(), Eq(2)); + + auto attr_value = ValueCast<Reference>(xml_attrs[0].compiled_value.get()); + ASSERT_THAT(attr_value, NotNull()); + EXPECT_THAT(attr_value->reference_type, Eq(Reference::Type::kResource)); + EXPECT_THAT(attr_value->id, Eq(0x01060001)); + + EXPECT_THAT(xml_attrs[1].compiled_value.get(), IsNull()); + EXPECT_THAT(xml_attrs[1].value, Eq("Hello World!")); +} + } // namespace aapt diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index 17d11a63553a..74ecf47cae4c 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -567,13 +567,10 @@ class PackageFlattener { } bool FlattenTypes(BigBuffer* buffer) { - // Sort the types by their IDs. They will be inserted into the StringPool in - // this order. - size_t expected_type_id = 1; for (const ResourceTableTypeView& type : package_.types) { - if (type.type == ResourceType::kStyleable) { - // Styleables aren't real Resource Types, they are represented in the R.java file. + if (type.type == ResourceType::kStyleable || type.type == ResourceType::kMacro) { + // Styleables and macros are not real resource types. continue; } diff --git a/tools/aapt2/format/binary/XmlFlattener_test.cpp b/tools/aapt2/format/binary/XmlFlattener_test.cpp index c24488b16153..d97e8882e5a2 100644 --- a/tools/aapt2/format/binary/XmlFlattener_test.cpp +++ b/tools/aapt2/format/binary/XmlFlattener_test.cpp @@ -222,7 +222,7 @@ TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) { android:id="@id/foo" app:foo="@id/foo" />)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); // The tree needs a custom DynamicRefTable since it is not using a standard app ID (0x7f). diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index 498d5a27d69d..ec331df480cd 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -656,6 +656,38 @@ static bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* o } out_ref->name = name_ref.ToResourceName(); } + if (pb_ref.type_flags() != 0) { + out_ref->type_flags = pb_ref.type_flags(); + } + out_ref->allow_raw = pb_ref.allow_raw(); + return true; +} + +static bool DeserializeMacroFromPb(const pb::MacroBody& pb_ref, Macro* out_ref, + std::string* out_error) { + out_ref->raw_value = pb_ref.raw_string(); + + if (pb_ref.has_style_string()) { + out_ref->style_string.str = pb_ref.style_string().str(); + for (const auto& span : pb_ref.style_string().spans()) { + out_ref->style_string.spans.emplace_back(Span{ + .name = span.name(), .first_char = span.start_index(), .last_char = span.end_index()}); + } + } + + for (const auto& untranslatable_section : pb_ref.untranslatable_sections()) { + out_ref->untranslatable_sections.emplace_back( + UntranslatableSection{.start = static_cast<size_t>(untranslatable_section.start_index()), + .end = static_cast<size_t>(untranslatable_section.end_index())}); + } + + for (const auto& namespace_decls : pb_ref.namespace_stack()) { + out_ref->alias_namespaces.emplace_back( + Macro::Namespace{.alias = namespace_decls.prefix(), + .package_name = namespace_decls.package_name(), + .is_private = namespace_decls.is_private()}); + } + return true; } @@ -801,6 +833,15 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value, value = std::move(plural); } break; + case pb::CompoundValue::kMacro: { + const pb::MacroBody& pb_macro = pb_compound_value.macro(); + auto macro = std::make_unique<Macro>(); + if (!DeserializeMacroFromPb(pb_macro, macro.get(), out_error)) { + return {}; + } + value = std::move(macro); + } break; + default: LOG(FATAL) << "unknown compound value: " << (int)pb_compound_value.value_case(); break; diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index f13f82da3102..d2f033683cc5 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -440,6 +440,36 @@ static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) if (ref.is_dynamic) { pb_ref->mutable_is_dynamic()->set_value(ref.is_dynamic); } + if (ref.type_flags) { + pb_ref->set_type_flags(*ref.type_flags); + } + pb_ref->set_allow_raw(ref.allow_raw); +} + +static void SerializeMacroToPb(const Macro& ref, pb::MacroBody* pb_macro) { + pb_macro->set_raw_string(ref.raw_value); + + auto pb_style_str = pb_macro->mutable_style_string(); + pb_style_str->set_str(ref.style_string.str); + for (const auto& span : ref.style_string.spans) { + auto pb_span = pb_style_str->add_spans(); + pb_span->set_name(span.name); + pb_span->set_start_index(span.first_char); + pb_span->set_end_index(span.last_char); + } + + for (const auto& untranslatable_section : ref.untranslatable_sections) { + auto pb_section = pb_macro->add_untranslatable_sections(); + pb_section->set_start_index(untranslatable_section.start); + pb_section->set_end_index(untranslatable_section.end); + } + + for (const auto& namespace_decls : ref.alias_namespaces) { + auto pb_namespace = pb_macro->add_namespace_stack(); + pb_namespace->set_prefix(namespace_decls.alias); + pb_namespace->set_package_name(namespace_decls.package_name); + pb_namespace->set_is_private(namespace_decls.is_private); + } } template <typename T> @@ -643,6 +673,11 @@ class ValueSerializer : public ConstValueVisitor { } } + void Visit(const Macro* macro) override { + pb::MacroBody* pb_macro = out_value_->mutable_compound_value()->mutable_macro(); + SerializeMacroToPb(*macro, pb_macro); + } + void VisitAny(const Value* unknown) override { LOG(FATAL) << "unimplemented value: " << *unknown; } diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp index 591ba14942cd..e563eda93e20 100644 --- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp @@ -894,4 +894,38 @@ TEST(ProtoSerializeTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSucce EXPECT_THAT(*(s->value), Eq("foo")); } +TEST(ProtoSerializeTest, SerializeMacro) { + auto original = std::make_unique<Macro>(); + original->raw_value = "\nThis being human is a guest house."; + original->style_string.str = " This being human is a guest house."; + original->style_string.spans.emplace_back(Span{.name = "b", .first_char = 12, .last_char = 16}); + original->untranslatable_sections.emplace_back(UntranslatableSection{.start = 12, .end = 17}); + original->alias_namespaces.emplace_back( + Macro::Namespace{.alias = "prefix", .package_name = "package.name", .is_private = true}); + + CloningValueTransformer cloner(nullptr); + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() + .Add(NewResourceBuilder("com.app.a:macro/foo") + .SetValue(original->Transform(cloner)) + .Build()) + .Build(); + + ResourceTable new_table; + pb::ResourceTable pb_table; + MockFileCollection files; + std::string error; + SerializeTableToPb(*table, &pb_table, context->GetDiagnostics()); + ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)); + EXPECT_THAT(error, IsEmpty()); + + Macro* deserialized = test::GetValue<Macro>(&new_table, "com.app.a:macro/foo"); + ASSERT_THAT(deserialized, NotNull()); + EXPECT_THAT(deserialized->raw_value, Eq(original->raw_value)); + EXPECT_THAT(deserialized->style_string.str, Eq(original->style_string.str)); + EXPECT_THAT(deserialized->style_string.spans, Eq(original->style_string.spans)); + EXPECT_THAT(deserialized->untranslatable_sections, Eq(original->untranslatable_sections)); + EXPECT_THAT(deserialized->alias_namespaces, Eq(original->alias_namespaces)); +} + } // namespace aapt diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp index e1e2e0135cf7..de6524dc7027 100644 --- a/tools/aapt2/java/JavaClassGenerator.cpp +++ b/tools/aapt2/java/JavaClassGenerator.cpp @@ -616,8 +616,9 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, for (const auto& package : table_->packages) { for (const auto& type : package->types) { - if (type->type == ResourceType::kAttrPrivate) { - // We generate these as part of the kAttr type, so skip them here. + if (type->type == ResourceType::kAttrPrivate || type->type == ResourceType::kMacro) { + // We generate kAttrPrivate as part of the kAttr type, so skip them here. + // Macros are not actual resources, so skip them as well. continue; } diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp index d08b61e5ff66..40395ed64fe3 100644 --- a/tools/aapt2/java/JavaClassGenerator_test.cpp +++ b/tools/aapt2/java/JavaClassGenerator_test.cpp @@ -570,4 +570,25 @@ TEST(JavaClassGeneratorTest, SortsDynamicAttributesAfterFrameworkAttributes) { EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_dynamic_attr=1;")); } +TEST(JavaClassGeneratorTest, SkipMacros) { + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .AddValue("android:macro/bar", ResourceId(0x01010000), test::AttributeBuilder().Build()) + .Build(); + + std::unique_ptr<IAaptContext> context = + test::ContextBuilder() + .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) + .SetNameManglerPolicy(NameManglerPolicy{"android"}) + .Build(); + JavaClassGenerator generator(context.get(), table.get(), {}); + + std::string output; + StringOutputStream out(&output); + EXPECT_TRUE(generator.Generate("android", &out)); + out.Flush(); + + EXPECT_THAT(output, Not(HasSubstr("bar"))); +} + } // namespace aapt diff --git a/tools/aapt2/java/ProguardRules_test.cpp b/tools/aapt2/java/ProguardRules_test.cpp index b7dfec3a6b28..e1040666e410 100644 --- a/tools/aapt2/java/ProguardRules_test.cpp +++ b/tools/aapt2/java/ProguardRules_test.cpp @@ -264,7 +264,7 @@ TEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) { </View>)"); foo_layout->file.name = test::ParseNameOrDie("com.foo:layout/foo"); - XmlReferenceLinker xml_linker; + XmlReferenceLinker xml_linker(nullptr); ASSERT_TRUE(xml_linker.Consume(context.get(), bar_layout.get())); ASSERT_TRUE(xml_linker.Consume(context.get(), foo_layout.get())); diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h index c9b8d3993959..be6c930b9284 100644 --- a/tools/aapt2/link/Linkers.h +++ b/tools/aapt2/link/Linkers.h @@ -133,12 +133,14 @@ class XmlNamespaceRemover : public IXmlResourceConsumer { // Once an XmlResource is processed by this linker, it is ready to be flattened. class XmlReferenceLinker : public IXmlResourceConsumer { public: - XmlReferenceLinker() = default; + explicit XmlReferenceLinker(ResourceTable* table) : table_(table) { + } bool Consume(IAaptContext* context, xml::XmlResource* resource) override; private: DISALLOW_COPY_AND_ASSIGN(XmlReferenceLinker); + ResourceTable* table_; }; } // namespace aapt diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp index 8e49fabe6a5c..4ac25bd6a0e0 100644 --- a/tools/aapt2/link/ReferenceLinker.cpp +++ b/tools/aapt2/link/ReferenceLinker.cpp @@ -21,6 +21,7 @@ #include "androidfw/ResourceTypes.h" #include "Diagnostics.h" +#include "ResourceParser.h" #include "ResourceTable.h" #include "ResourceUtils.h" #include "ResourceValues.h" @@ -37,128 +38,153 @@ using ::android::StringPiece; using ::android::base::StringPrintf; namespace aapt { - namespace { +struct LoggingResourceName { + LoggingResourceName(const Reference& ref, const CallSite& callsite, + const xml::IPackageDeclStack* decls) + : ref_(ref), callsite_(callsite), decls_(decls) { + } -// The ReferenceLinkerVisitor will follow all references and make sure they point -// to resources that actually exist, either in the local resource table, or as external -// symbols. Once the target resource has been found, the ID of the resource will be assigned -// to the reference object. -// -// NOTE: All of the entries in the ResourceTable must be assigned IDs. -class ReferenceLinkerVisitor : public DescendingValueVisitor { - public: - using DescendingValueVisitor::Visit; - - ReferenceLinkerVisitor(const CallSite& callsite, IAaptContext* context, SymbolTable* symbols, - StringPool* string_pool, xml::IPackageDeclStack* decl) - : callsite_(callsite), - context_(context), - symbols_(symbols), - package_decls_(decl), - string_pool_(string_pool) {} - - void Visit(Reference* ref) override { - if (!ReferenceLinker::LinkReference(callsite_, ref, context_, symbols_, package_decls_)) { - error_ = true; - } + const Reference& ref_; + const CallSite& callsite_; + const xml::IPackageDeclStack* decls_; +}; + +inline ::std::ostream& operator<<(::std::ostream& out, const LoggingResourceName& name) { + if (!name.ref_.name) { + out << name.ref_.id.value(); + return out; } - // We visit the Style specially because during this phase, values of attributes are - // all RawString values. Now that we are expected to resolve all symbols, we can - // lookup the attributes to find out which types are allowed for the attributes' values. - void Visit(Style* style) override { - if (style->parent) { - Visit(&style->parent.value()); - } + out << name.ref_.name.value(); + + Reference fully_qualified = name.ref_; + xml::ResolvePackage(name.decls_, &fully_qualified); + + ResourceName& full_name = fully_qualified.name.value(); + if (full_name.package.empty()) { + full_name.package = name.callsite_.package; + } - for (Style::Entry& entry : style->entries) { - std::string err_str; + if (full_name != name.ref_.name.value()) { + out << " (aka " << full_name << ")"; + } + return out; +} - // Transform the attribute reference so that it is using the fully qualified package - // name. This will also mark the reference as being able to see private resources if - // there was a '*' in the reference or if the package came from the private namespace. - Reference transformed_reference = entry.key; - ResolvePackage(package_decls_, &transformed_reference); +} // namespace - // Find the attribute in the symbol table and check if it is visible from this callsite. - const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveAttributeCheckVisibility( - transformed_reference, callsite_, context_, symbols_, &err_str); - if (symbol) { - // Assign our style key the correct ID. The ID may not exist. - entry.key.id = symbol->id; - - // Try to convert the value to a more specific, typed value based on the attribute it is - // set to. - entry.value = ParseValueWithAttribute(std::move(entry.value), symbol->attribute.get()); - - // Link/resolve the final value (mostly if it's a reference). - entry.value->Accept(this); - - // Now verify that the type of this item is compatible with the - // attribute it is defined for. We pass `nullptr` as the DiagMessage so that this - // check is fast and we avoid creating a DiagMessage when the match is successful. - if (!symbol->attribute->Matches(*entry.value, nullptr)) { - // The actual type of this item is incompatible with the attribute. - DiagMessage msg(entry.key.GetSource()); - - // Call the matches method again, this time with a DiagMessage so we fill in the actual - // error message. - symbol->attribute->Matches(*entry.value, &msg); - context_->GetDiagnostics()->Error(msg); - error_ = true; - } +std::unique_ptr<Reference> ReferenceLinkerTransformer::TransformDerived(const Reference* value) { + auto linked_item = + ReferenceLinker::LinkReference(callsite_, *value, context_, symbols_, table_, package_decls_); + if (linked_item) { + auto linked_item_ptr = linked_item.release(); + if (auto ref = ValueCast<Reference>(linked_item_ptr)) { + return std::unique_ptr<Reference>(ref); + } + context_->GetDiagnostics()->Error(DiagMessage(value->GetSource()) + << "value of '" + << LoggingResourceName(*value, callsite_, package_decls_) + << "' must be a resource reference"); + delete linked_item_ptr; + } + + error_ = true; + return CloningValueTransformer::TransformDerived(value); +} + +std::unique_ptr<Style> ReferenceLinkerTransformer::TransformDerived(const Style* style) { + // We visit the Style specially because during this phase, values of attributes are either + // RawString or Reference values. Now that we are expected to resolve all symbols, we can lookup + // the attributes to find out which types are allowed for the attributes' values. + auto new_style = CloningValueTransformer::TransformDerived(style); + if (new_style->parent) { + new_style->parent = *TransformDerived(&style->parent.value()); + } - } else { + for (Style::Entry& entry : new_style->entries) { + std::string err_str; + + // Transform the attribute reference so that it is using the fully qualified package + // name. This will also mark the reference as being able to see private resources if + // there was a '*' in the reference or if the package came from the private namespace. + Reference transformed_reference = entry.key; + ResolvePackage(package_decls_, &transformed_reference); + + // Find the attribute in the symbol table and check if it is visible from this callsite. + const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveAttributeCheckVisibility( + transformed_reference, callsite_, context_, symbols_, &err_str); + if (symbol) { + // Assign our style key the correct ID. The ID may not exist. + entry.key.id = symbol->id; + + // Link/resolve the final value if it's a reference. + entry.value = entry.value->Transform(*this); + + // Try to convert the value to a more specific, typed value based on the attribute it is + // set to. + entry.value = ParseValueWithAttribute(std::move(entry.value), symbol->attribute.get()); + + // Now verify that the type of this item is compatible with the + // attribute it is defined for. We pass `nullptr` as the DiagMessage so that this + // check is fast and we avoid creating a DiagMessage when the match is successful. + if (!symbol->attribute->Matches(*entry.value, nullptr)) { + // The actual type of this item is incompatible with the attribute. DiagMessage msg(entry.key.GetSource()); - msg << "style attribute '"; - ReferenceLinker::WriteResourceName(entry.key, callsite_, package_decls_, &msg); - msg << "' " << err_str; + + // Call the matches method again, this time with a DiagMessage so we fill in the actual + // error message. + symbol->attribute->Matches(*entry.value, &msg); context_->GetDiagnostics()->Error(msg); error_ = true; } + } else { + context_->GetDiagnostics()->Error(DiagMessage(entry.key.GetSource()) + << "style attribute '" + << LoggingResourceName(entry.key, callsite_, package_decls_) + << "' " << err_str); + + error_ = true; } } + return new_style; +} - bool HasError() { - return error_; +std::unique_ptr<Item> ReferenceLinkerTransformer::TransformItem(const Reference* value) { + auto linked_value = + ReferenceLinker::LinkReference(callsite_, *value, context_, symbols_, table_, package_decls_); + if (linked_value) { + return linked_value; } + error_ = true; + return CloningValueTransformer::TransformDerived(value); +} - private: - DISALLOW_COPY_AND_ASSIGN(ReferenceLinkerVisitor); - - // Transform a RawString value into a more specific, appropriate value, based on the - // Attribute. If a non RawString value is passed in, this is an identity transform. - std::unique_ptr<Item> ParseValueWithAttribute(std::unique_ptr<Item> value, - const Attribute* attr) { - if (RawString* raw_string = ValueCast<RawString>(value.get())) { - std::unique_ptr<Item> transformed = - ResourceUtils::TryParseItemForAttribute(*raw_string->value, attr); - - // If we could not parse as any specific type, try a basic STRING. - if (!transformed && (attr->type_mask & android::ResTable_map::TYPE_STRING)) { - StringBuilder string_builder; - string_builder.AppendText(*raw_string->value); - if (string_builder) { - transformed = - util::make_unique<String>(string_pool_->MakeRef(string_builder.to_string())); - } +// Transform a RawString value into a more specific, appropriate value, based on the +// Attribute. If a non RawString value is passed in, this is an identity transform. +std::unique_ptr<Item> ReferenceLinkerTransformer::ParseValueWithAttribute( + std::unique_ptr<Item> value, const Attribute* attr) { + if (RawString* raw_string = ValueCast<RawString>(value.get())) { + std::unique_ptr<Item> transformed = + ResourceUtils::TryParseItemForAttribute(*raw_string->value, attr); + + // If we could not parse as any specific type, try a basic STRING. + if (!transformed && (attr->type_mask & android::ResTable_map::TYPE_STRING)) { + StringBuilder string_builder; + string_builder.AppendText(*raw_string->value); + if (string_builder) { + transformed = util::make_unique<String>(pool_->MakeRef(string_builder.to_string())); } + } - if (transformed) { - return transformed; - } + if (transformed) { + return transformed; } - return value; } + return value; +} - const CallSite& callsite_; - IAaptContext* context_; - SymbolTable* symbols_; - xml::IPackageDeclStack* package_decls_; - StringPool* string_pool_; - bool error_ = false; -}; +namespace { class EmptyDeclStack : public xml::IPackageDeclStack { public: @@ -175,6 +201,27 @@ class EmptyDeclStack : public xml::IPackageDeclStack { DISALLOW_COPY_AND_ASSIGN(EmptyDeclStack); }; +struct MacroDeclStack : public xml::IPackageDeclStack { + explicit MacroDeclStack(std::vector<Macro::Namespace> namespaces) + : alias_namespaces_(std::move(namespaces)) { + } + + Maybe<xml::ExtractedPackage> TransformPackageAlias(const StringPiece& alias) const override { + if (alias.empty()) { + return xml::ExtractedPackage{{}, true /*private*/}; + } + for (auto it = alias_namespaces_.rbegin(); it != alias_namespaces_.rend(); ++it) { + if (alias == StringPiece(it->alias)) { + return xml::ExtractedPackage{it->package_name, it->is_private}; + } + } + return {}; + } + + private: + std::vector<Macro::Namespace> alias_namespaces_; +}; + // The symbol is visible if it is public, or if the reference to it is requesting private access // or if the callsite comes from the same package. bool IsSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref, @@ -220,8 +267,6 @@ const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(const Reference& refer // If the callsite package is the same as the current compilation package, // check the feature split dependencies as well. Feature split resources // can be referenced without a namespace, just like the base package. - // TODO: modify the package name of included splits instead of having the - // symbol table look up the resource in in every package. b/136105066 if (callsite.package == context->GetCompilationPackage()) { const auto& split_name_dependencies = context->GetSplitNameDependencies(); for (const std::string& split_name : split_name_dependencies) { @@ -295,29 +340,6 @@ Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& return xml::AaptAttribute(*symbol->attribute, symbol->id); } -void ReferenceLinker::WriteResourceName(const Reference& ref, const CallSite& callsite, - const xml::IPackageDeclStack* decls, DiagMessage* out_msg) { - CHECK(out_msg != nullptr); - if (!ref.name) { - *out_msg << ref.id.value(); - return; - } - - *out_msg << ref.name.value(); - - Reference fully_qualified = ref; - xml::ResolvePackage(decls, &fully_qualified); - - ResourceName& full_name = fully_qualified.name.value(); - if (full_name.package.empty()) { - full_name.package = callsite.package; - } - - if (full_name != ref.name.value()) { - *out_msg << " (aka " << full_name << ")"; - } -} - void ReferenceLinker::WriteAttributeName(const Reference& ref, const CallSite& callsite, const xml::IPackageDeclStack* decls, DiagMessage* out_msg) { @@ -348,18 +370,71 @@ void ReferenceLinker::WriteAttributeName(const Reference& ref, const CallSite& c } } -bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* reference, - IAaptContext* context, SymbolTable* symbols, - const xml::IPackageDeclStack* decls) { - CHECK(reference != nullptr); - if (!reference->name && !reference->id) { +std::unique_ptr<Item> ReferenceLinker::LinkReference(const CallSite& callsite, + const Reference& reference, + IAaptContext* context, SymbolTable* symbols, + ResourceTable* table, + const xml::IPackageDeclStack* decls) { + if (!reference.name && !reference.id) { // This is @null. - return true; + return std::make_unique<Reference>(reference); } - Reference transformed_reference = *reference; + Reference transformed_reference = reference; xml::ResolvePackage(decls, &transformed_reference); + if (transformed_reference.name.value().type == ResourceType::kMacro) { + if (transformed_reference.name.value().package.empty()) { + transformed_reference.name.value().package = callsite.package; + } + + auto result = table->FindResource(transformed_reference.name.value()); + if (!result || result.value().entry->values.empty()) { + context->GetDiagnostics()->Error( + DiagMessage(reference.GetSource()) + << "failed to find definition for " + << LoggingResourceName(transformed_reference, callsite, decls)); + return {}; + } + + auto& macro_values = result.value().entry->values; + CHECK(macro_values.size() == 1) << "Macros can only be defined in the default configuration."; + + auto macro = ValueCast<Macro>(macro_values[0]->value.get()); + CHECK(macro != nullptr) << "Value of macro resource is not a Macro (actual " + << *macro_values[0]->value << ")"; + + // Re-create the state used to parse the macro tag to compile the macro contents as if it was + // defined inline + uint32_t type_flags = 0; + if (reference.type_flags.has_value()) { + type_flags = reference.type_flags.value(); + } + + MacroDeclStack namespace_stack(macro->alias_namespaces); + FlattenedXmlSubTree sub_tree{.raw_value = macro->raw_value, + .style_string = macro->style_string, + .untranslatable_sections = macro->untranslatable_sections, + .namespace_resolver = &namespace_stack, + .source = macro->GetSource()}; + + auto new_value = ResourceParser::ParseXml(sub_tree, type_flags, reference.allow_raw, *table, + macro_values[0]->config, *context->GetDiagnostics()); + if (new_value == nullptr) { + context->GetDiagnostics()->Error( + DiagMessage(reference.GetSource()) + << "failed to substitute macro " + << LoggingResourceName(transformed_reference, callsite, decls) + << ": failed to parse contents as one of type(s) " << Attribute::MaskString(type_flags)); + return {}; + } + + if (auto ref = ValueCast<Reference>(new_value.get())) { + return LinkReference(callsite, *ref, context, symbols, table, decls); + } + return new_value; + } + std::string err_str; const SymbolTable::Symbol* s = ResolveSymbolCheckVisibility(transformed_reference, callsite, context, symbols, &err_str); @@ -367,17 +442,17 @@ bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* referen // The ID may not exist. This is fine because of the possibility of building // against libraries without assigned IDs. // Ex: Linking against own resources when building a static library. - reference->id = s->id; - reference->is_dynamic = s->is_dynamic; - return true; + auto new_ref = std::make_unique<Reference>(reference); + new_ref->id = s->id; + new_ref->is_dynamic = s->is_dynamic; + return std::move(new_ref); } - DiagMessage error_msg(reference->GetSource()); - error_msg << "resource "; - WriteResourceName(*reference, callsite, decls, &error_msg); - error_msg << " " << err_str; - context->GetDiagnostics()->Error(error_msg); - return false; + context->GetDiagnostics()->Error(DiagMessage(reference.GetSource()) + << "resource " + << LoggingResourceName(transformed_reference, callsite, decls) + << " " << err_str); + return {}; } bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) { @@ -412,14 +487,15 @@ bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) { // The context of this resource is the package in which it is defined. const CallSite callsite{name.package}; - ReferenceLinkerVisitor visitor(callsite, context, context->GetExternalSymbols(), - &table->string_pool, &decl_stack); + ReferenceLinkerTransformer reference_transformer(callsite, context, + context->GetExternalSymbols(), + &table->string_pool, table, &decl_stack); for (auto& config_value : entry->values) { - config_value->value->Accept(&visitor); + config_value->value = config_value->value->Transform(reference_transformer); } - if (visitor.HasError()) { + if (reference_transformer.HasError()) { error = true; } } diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h index 1256709edbf4..770f1e500ac0 100644 --- a/tools/aapt2/link/ReferenceLinker.h +++ b/tools/aapt2/link/ReferenceLinker.h @@ -28,6 +28,41 @@ namespace aapt { +// A ValueTransformer that returns fully linked versions of resource and macro references. +class ReferenceLinkerTransformer : public CloningValueTransformer { + public: + ReferenceLinkerTransformer(const CallSite& callsite, IAaptContext* context, SymbolTable* symbols, + StringPool* string_pool, ResourceTable* table, + xml::IPackageDeclStack* decl) + : CloningValueTransformer(string_pool), + callsite_(callsite), + context_(context), + symbols_(symbols), + table_(table), + package_decls_(decl) { + } + + std::unique_ptr<Reference> TransformDerived(const Reference* value) override; + std::unique_ptr<Item> TransformItem(const Reference* value) override; + std::unique_ptr<Style> TransformDerived(const Style* value) override; + + bool HasError() { + return error_; + } + + private: + // Transform a RawString value into a more specific, appropriate value, based on the + // Attribute. If a non RawString value is passed in, this is an identity transform. + std::unique_ptr<Item> ParseValueWithAttribute(std::unique_ptr<Item> value, const Attribute* attr); + + const CallSite& callsite_; + IAaptContext* context_; + SymbolTable* symbols_; + ResourceTable* table_; + xml::IPackageDeclStack* package_decls_; + bool error_ = false; +}; + // Resolves all references to resources in the ResourceTable and assigns them IDs. // The ResourceTable must already have IDs assigned to each resource. // Once the ResourceTable is processed by this linker, it is ready to be flattened. @@ -70,19 +105,28 @@ class ReferenceLinker : public IResourceTableConsumer { // Writes the resource name to the DiagMessage, using the // "orig_name (aka <transformed_name>)" syntax. - static void WriteResourceName(const Reference& orig, const CallSite& callsite, - const xml::IPackageDeclStack* decls, DiagMessage* out_msg); + /*static void WriteResourceName(const Reference& orig, const CallSite& callsite, + const xml::IPackageDeclStack* decls, DiagMessage* out_msg);*/ // Same as WriteResourceName but omits the 'attr' part. static void WriteAttributeName(const Reference& ref, const CallSite& callsite, const xml::IPackageDeclStack* decls, DiagMessage* out_msg); - // Transforms the package name of the reference to the fully qualified package name using - // the xml::IPackageDeclStack, then mangles and looks up the symbol. If the symbol is visible - // to the reference at the callsite, the reference is updated with an ID. - // Returns false on failure, and an error message is logged to the IDiagnostics in the context. - static bool LinkReference(const CallSite& callsite, Reference* reference, IAaptContext* context, - SymbolTable* symbols, const xml::IPackageDeclStack* decls); + // Returns a fully linked version a resource reference. + // + // If the reference points to a non-macro resource, the xml::IPackageDeclStack is used to + // determine the fully qualified name of the referenced resource. If the symbol is visible + // to the reference at the callsite, a copy of the reference with an updated updated ID is + // returned. + // + // If the reference points to a macro, the ResourceTable is used to find the macro definition and + // substitute its contents in place of the reference. + // + // Returns nullptr on failure, and an error message is logged to the IDiagnostics in the context. + static std::unique_ptr<Item> LinkReference(const CallSite& callsite, const Reference& reference, + IAaptContext* context, SymbolTable* symbols, + ResourceTable* table, + const xml::IPackageDeclStack* decls); // Links all references in the ResourceTable. bool Consume(IAaptContext* context, ResourceTable* table) override; diff --git a/tools/aapt2/link/ReferenceLinker_test.cpp b/tools/aapt2/link/ReferenceLinker_test.cpp index 228c5bd743a0..2d8f0d39053f 100644 --- a/tools/aapt2/link/ReferenceLinker_test.cpp +++ b/tools/aapt2/link/ReferenceLinker_test.cpp @@ -365,4 +365,22 @@ TEST(ReferenceLinkerTest, ReferenceSymbolFromOtherSplit) { EXPECT_THAT(s, IsNull()); } +TEST(ReferenceLinkerTest, MacroFailToFindDefinition) { + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .AddReference("com.app.test:string/foo", ResourceId(0x7f020000), "com.app.test:macro/bar") + .Build(); + + std::unique_ptr<IAaptContext> context = + test::ContextBuilder() + .SetCompilationPackage("com.app.test") + .SetPackageId(0x7f) + .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"}) + .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get())) + .Build(); + + ReferenceLinker linker; + ASSERT_FALSE(linker.Consume(context.get(), table.get())); +} + } // namespace aapt diff --git a/tools/aapt2/link/XmlCompatVersioner_test.cpp b/tools/aapt2/link/XmlCompatVersioner_test.cpp index a98ab0f76de4..d63809615a5b 100644 --- a/tools/aapt2/link/XmlCompatVersioner_test.cpp +++ b/tools/aapt2/link/XmlCompatVersioner_test.cpp @@ -82,7 +82,7 @@ TEST_F(XmlCompatVersionerTest, NoRulesOnlyStripsAndCopies) { app:foo="16dp" foo="bar"/>)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); XmlCompatVersioner::Rules rules; @@ -121,7 +121,7 @@ TEST_F(XmlCompatVersionerTest, SingleRule) { app:foo="16dp" foo="bar"/>)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); XmlCompatVersioner::Rules rules; @@ -181,7 +181,7 @@ TEST_F(XmlCompatVersionerTest, ChainedRule) { <View xmlns:android="http://schemas.android.com/apk/res/android" android:paddingHorizontal="24dp" />)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); XmlCompatVersioner::Rules rules; @@ -256,7 +256,7 @@ TEST_F(XmlCompatVersionerTest, DegradeRuleOverridesExistingAttribute) { android:paddingLeft="16dp" android:paddingRight="16dp"/>)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); Item* padding_horizontal_value = diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp index c3c16b92f712..aaa085e2eb15 100644 --- a/tools/aapt2/link/XmlReferenceLinker.cpp +++ b/tools/aapt2/link/XmlReferenceLinker.cpp @@ -33,49 +33,18 @@ namespace aapt { namespace { -// Visits all references (including parents of styles, references in styles, arrays, etc) and -// links their symbolic name to their Resource ID, performing mangling and package aliasing -// as needed. -class ReferenceVisitor : public DescendingValueVisitor { - public: - using DescendingValueVisitor::Visit; - - ReferenceVisitor(const CallSite& callsite, IAaptContext* context, SymbolTable* symbols, - xml::IPackageDeclStack* decls) - : callsite_(callsite), context_(context), symbols_(symbols), decls_(decls), error_(false) {} - - void Visit(Reference* ref) override { - if (!ReferenceLinker::LinkReference(callsite_, ref, context_, symbols_, decls_)) { - error_ = true; - } - } - - bool HasError() const { - return error_; - } - - private: - DISALLOW_COPY_AND_ASSIGN(ReferenceVisitor); - - const CallSite& callsite_; - IAaptContext* context_; - SymbolTable* symbols_; - xml::IPackageDeclStack* decls_; - bool error_; -}; - // Visits each xml Element and compiles the attributes within. class XmlVisitor : public xml::PackageAwareVisitor { public: using xml::PackageAwareVisitor::Visit; - XmlVisitor(const Source& source, const CallSite& callsite, IAaptContext* context, - SymbolTable* symbols) + XmlVisitor(const Source& source, StringPool* pool, const CallSite& callsite, + IAaptContext* context, ResourceTable* table, SymbolTable* symbols) : source_(source), callsite_(callsite), context_(context), symbols_(symbols), - reference_visitor_(callsite, context, symbols, this) { + reference_transformer_(callsite, context, symbols, pool, table, this) { } void Visit(xml::Element* el) override { @@ -127,7 +96,7 @@ class XmlVisitor : public xml::PackageAwareVisitor { if (attr.compiled_value) { // With a compiledValue, we must resolve the reference and assign it an ID. attr.compiled_value->SetSource(source); - attr.compiled_value->Accept(&reference_visitor_); + attr.compiled_value = attr.compiled_value->Transform(reference_transformer_); } else if ((attribute->type_mask & android::ResTable_map::TYPE_STRING) == 0) { // We won't be able to encode this as a string. DiagMessage msg(source); @@ -143,7 +112,7 @@ class XmlVisitor : public xml::PackageAwareVisitor { } bool HasError() { - return error_ || reference_visitor_.HasError(); + return error_ || reference_transformer_.HasError(); } private: @@ -154,7 +123,7 @@ class XmlVisitor : public xml::PackageAwareVisitor { IAaptContext* context_; SymbolTable* symbols_; - ReferenceVisitor reference_visitor_; + ReferenceLinkerTransformer reference_transformer_; bool error_ = false; }; @@ -173,7 +142,8 @@ bool XmlReferenceLinker::Consume(IAaptContext* context, xml::XmlResource* resour callsite.package = context->GetCompilationPackage(); } - XmlVisitor visitor(resource->file.source, callsite, context, context->GetExternalSymbols()); + XmlVisitor visitor(resource->file.source, &resource->string_pool, callsite, context, table_, + context->GetExternalSymbols()); if (resource->root) { resource->root->Accept(&visitor); return !visitor.HasError(); diff --git a/tools/aapt2/link/XmlReferenceLinker_test.cpp b/tools/aapt2/link/XmlReferenceLinker_test.cpp index 0ce2e50d6e44..ddf5b9a22c2f 100644 --- a/tools/aapt2/link/XmlReferenceLinker_test.cpp +++ b/tools/aapt2/link/XmlReferenceLinker_test.cpp @@ -91,7 +91,7 @@ TEST_F(XmlReferenceLinkerTest, LinkBasicAttributes) { nonAaptAttrRef="@id/id" class="hello" />)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); xml::Element* view_el = doc->root.get(); @@ -144,7 +144,7 @@ TEST_F(XmlReferenceLinkerTest, PrivateSymbolsAreNotLinked) { <View xmlns:android="http://schemas.android.com/apk/res/android" android:colorAccent="@android:color/hidden" />)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_FALSE(linker.Consume(context_.get(), doc.get())); } @@ -153,7 +153,7 @@ TEST_F(XmlReferenceLinkerTest, PrivateSymbolsAreLinkedWhenReferenceHasStarPrefix <View xmlns:android="http://schemas.android.com/apk/res/android" android:colorAccent="@*android:color/hidden" />)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); } @@ -162,7 +162,7 @@ TEST_F(XmlReferenceLinkerTest, LinkMangledAttributes) { <View xmlns:support="http://schemas.android.com/apk/res/com.android.support" support:colorAccent="#ff0000" />)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); xml::Element* view_el = doc->root.get(); @@ -181,7 +181,7 @@ TEST_F(XmlReferenceLinkerTest, LinkAutoResReference) { <View xmlns:app="http://schemas.android.com/apk/res-auto" app:colorAccent="@app:color/red" />)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); xml::Element* view_el = doc->root.get(); @@ -203,7 +203,7 @@ TEST_F(XmlReferenceLinkerTest, LinkViewWithShadowedPackageAlias) { <View xmlns:app="http://schemas.android.com/apk/res/com.app.test" app:attr="@app:id/id"/> </View>)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); xml::Element* view_el = doc->root.get(); @@ -239,7 +239,7 @@ TEST_F(XmlReferenceLinkerTest, LinkViewWithLocalPackageAndAliasOfTheSameName) { <View xmlns:android="http://schemas.android.com/apk/res/com.app.test" android:attr="@id/id"/>)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); xml::Element* view_el = doc->root.get(); @@ -261,7 +261,7 @@ TEST_F(XmlReferenceLinkerTest, AddAngleOnGradientForAndroidQ) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDomForPackageName(context_.get(), R"( <gradient />)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); xml::Element* gradient_el = doc->root.get(); @@ -283,7 +283,7 @@ TEST_F(XmlReferenceLinkerTest, DoNotOverwriteAngleOnGradientForAndroidQ) { <gradient xmlns:android="http://schemas.android.com/apk/res/android" android:angle="90"/>)"); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); xml::Element* gradient_el = doc->root.get(); @@ -305,7 +305,7 @@ TEST_F(XmlReferenceLinkerTest, DoNotOverwriteAngleOnGradientForPostAndroidQ) { <gradient xmlns:android="http://schemas.android.com/apk/res/android" />)"); context_->SetMinSdkVersion(30); - XmlReferenceLinker linker; + XmlReferenceLinker linker(nullptr); ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); xml::Element* gradient_el = doc->root.get(); diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp index a023494ad8f7..182203d397c3 100644 --- a/tools/aapt2/xml/XmlPullParser.cpp +++ b/tools/aapt2/xml/XmlPullParser.cpp @@ -177,6 +177,10 @@ const std::string& XmlPullParser::element_name() const { return event_queue_.front().data2; } +const std::vector<XmlPullParser::PackageDecl>& XmlPullParser::package_decls() const { + return package_aliases_; +} + XmlPullParser::const_iterator XmlPullParser::begin_attributes() const { return event_queue_.front().attributes.begin(); } diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h index 6ebaa285745b..5da2d4b10a4b 100644 --- a/tools/aapt2/xml/XmlPullParser.h +++ b/tools/aapt2/xml/XmlPullParser.h @@ -123,6 +123,13 @@ class XmlPullParser : public IPackageDeclStack { */ Maybe<ExtractedPackage> TransformPackageAlias(const android::StringPiece& alias) const override; + struct PackageDecl { + std::string prefix; + ExtractedPackage package; + }; + + const std::vector<PackageDecl>& package_decls() const; + // // Remaining methods are for retrieving information about attributes // associated with a StartElement. @@ -180,11 +187,6 @@ class XmlPullParser : public IPackageDeclStack { const std::string empty_; size_t depth_; std::stack<std::string> namespace_uris_; - - struct PackageDecl { - std::string prefix; - ExtractedPackage package; - }; std::vector<PackageDecl> package_aliases_; }; |