diff options
946 files changed, 20259 insertions, 11491 deletions
diff --git a/.prebuilt_info/OWNERS b/.prebuilt_info/OWNERS new file mode 100644 index 000000000000..eb8b89b10e83 --- /dev/null +++ b/.prebuilt_info/OWNERS @@ -0,0 +1 @@ +per-file prebuilt_info_packages_CtsShim_*.asciipb = file:/packages/CtsShim/OWNERS diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb index 29bcfe046b98..1bd90a8eafae 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "6508977" + build_id: "7197701" target: "CtsShim" source_file: "aosp_arm64/CtsShimPriv.apk" } @@ -8,5 +8,5 @@ drops { version: "" version_group: "" git_project: "platform/frameworks/base" - git_branch: "rvc-dev" + git_branch: "sc-dev" } diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb index be172e6122cf..544bca029888 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "6508977" + build_id: "7197701" target: "CtsShim" source_file: "aosp_arm64/CtsShim.apk" } @@ -8,5 +8,5 @@ drops { version: "" version_group: "" git_project: "platform/frameworks/base" - git_branch: "rvc-dev" + git_branch: "sc-dev" } diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb index 13eca13c9308..72386bb88465 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "6508977" + build_id: "7197701" target: "CtsShim" source_file: "aosp_x86_64/CtsShimPriv.apk" } @@ -8,5 +8,5 @@ drops { version: "" version_group: "" git_project: "platform/frameworks/base" - git_branch: "rvc-dev" + git_branch: "sc-dev" } diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb index 2e863fe57f3c..893eac214daa 100644 --- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb +++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb @@ -1,6 +1,6 @@ drops { android_build_drop { - build_id: "6508977" + build_id: "7197701" target: "CtsShim" source_file: "aosp_x86_64/CtsShim.apk" } @@ -8,5 +8,5 @@ drops { version: "" version_group: "" git_project: "platform/frameworks/base" - git_branch: "rvc-dev" + git_branch: "sc-dev" } diff --git a/Android.bp b/Android.bp index c5980b911b17..9690969305bf 100644 --- a/Android.bp +++ b/Android.bp @@ -584,7 +584,7 @@ java_library { "android.hardware.vibrator-V2-java", "android.security.apc-java", "android.security.authorization-java", - "android.security.usermanager-java", + "android.security.maintenance-java", "android.security.vpnprofilestore-java", "android.system.keystore2-V1-java", "android.system.suspend.control.internal-java", @@ -665,9 +665,8 @@ java_defaults { ], required: [ "framework-platform-compat-config", - // TODO: remove gps_debug, cec_config.xml and protolog.conf.json when the build system propagates "required" properly. + // TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly. "gps_debug.conf", - "cec_config.xml", "icu4j-platform-compat-config", "libcore-platform-compat-config", "protolog.conf.json.gz", diff --git a/TEST_MAPPING b/TEST_MAPPING index d08c52782fb3..9ceef6bbe8a3 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -82,5 +82,65 @@ { "name": "ManagedProfileLifecycleStressTest" } - ] + ], + "auto-postsubmit": [ + // Test tag for automotive targets. These are only running in postsubmit so as to harden the + // automotive targets to avoid introducing additional test flake and build time. The plan for + // presubmit testing for auto is to augment the existing tests to cover auto use cases as well. + // Additionally, this tag is used in targeted test suites to limit resource usage on the test + // infra during the hardening phase. + // TODO: this tag to be removed once the above is no longer an issue. + { + "name": "FrameworksUiServicesTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "ExtServicesUnitTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TestablesTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-annotation": "android.platform.test.annotations.Presubmit" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] + }, + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-annotation": "android.platform.test.annotations.Presubmit" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "org.junit.Ignore" + } + ] + } + ] } diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java index da446bf1e7c6..a62bb504debc 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java @@ -19,19 +19,10 @@ import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.SystemService; import android.content.Context; -import android.os.Bundle; -import android.os.ParcelableException; -import android.os.RemoteException; -import com.android.internal.infra.AndroidFuture; import com.android.internal.util.Preconditions; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -246,349 +237,9 @@ public class AppSearchManager { mService, mContext.getUserId(), getPackageName(), executor, callback); } - /** - * Sets the schema being used by documents provided to the {@link #putDocuments} method. - * - * <p>The schema provided here is compared to the stored copy of the schema previously supplied - * to {@link #setSchema}, if any, to determine how to treat existing documents. The following - * types of schema modifications are always safe and are made without deleting any existing - * documents: - * - * <ul> - * <li>Addition of new types - * <li>Addition of new {@link - * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or - * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED - * REPEATED} properties to a type - * <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an {@link - * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} - * property into a {@link - * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} - * property. - * </ul> - * - * <p>The following types of schema changes are not backwards-compatible: - * - * <ul> - * <li>Removal of an existing type - * <li>Removal of a property from a type - * <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property - * <li>For properties of {@code GenericDocument} type, changing the schema type of {@code - * GenericDocument}s of that property - * <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an {@link - * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} - * property into a {@link - * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} - * property). - * <li>Adding a {@link - * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} - * property. - * </ul> - * - * <p>Supplying a schema with such changes will result in this call returning an {@link - * AppSearchResult} with a code of {@link AppSearchResult#RESULT_INVALID_SCHEMA} and an error - * message describing the incompatibility. In this case the previously set schema will remain - * active. - * - * <p>If you need to make non-backwards-compatible changes as described above, instead use the - * {@link #setSchema(List, boolean)} method with the {@code forceOverride} parameter set to - * {@code true}. - * - * <p>It is a no-op to set the same schema as has been previously set; this is handled - * efficiently. - * - * @param request The schema update request. - * @return the result of performing this operation. - * @hide - * @deprecated use {@link AppSearchSession#setSchema} instead. - */ - @NonNull - public AppSearchResult<Void> setSchema(@NonNull SetSchemaRequest request) { - Preconditions.checkNotNull(request); - // TODO: This should use com.android.internal.infra.RemoteStream or another mechanism to - // avoid binder limits. - List<Bundle> schemaBundles = new ArrayList<>(request.getSchemas().size()); - for (AppSearchSchema schema : request.getSchemas()) { - schemaBundles.add(schema.getBundle()); - } - AndroidFuture<AppSearchResult> future = new AndroidFuture<>(); - try { - mService.setSchema( - getPackageName(), - DEFAULT_DATABASE_NAME, - schemaBundles, - new ArrayList<>(request.getSchemasNotDisplayedBySystem()), - /*schemasPackageAccessible=*/ Collections.emptyMap(), - request.isForceOverride(), - mContext.getUserId(), - new IAppSearchResultCallback.Stub() { - public void onResult(AppSearchResult result) { - future.complete(result); - } - }); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return getFutureOrThrow(future); - } - - /** - * Index {@link GenericDocument}s into AppSearch. - * - * <p>You should not call this method directly; instead, use the {@code - * AppSearch#putDocuments()} API provided by JetPack. - * - * <p>Each {@link GenericDocument}'s {@code schemaType} field must be set to the name of a - * schema type previously registered via the {@link #setSchema} method. - * - * @param request {@link PutDocumentsRequest} containing documents to be indexed - * @return The pending result of performing this operation. The keys of the returned {@link - * AppSearchBatchResult} are the URIs of the input documents. The values are {@code null} if - * they were successfully indexed, or a failed {@link AppSearchResult} otherwise. - * @throws RuntimeException If an error occurred during the execution. - * @hide - * @deprecated use {@link AppSearchSession#put} instead. - */ - public AppSearchBatchResult<String, Void> putDocuments(@NonNull PutDocumentsRequest request) { - // TODO(b/146386470): Transmit these documents as a RemoteStream instead of sending them in - // one big list. - List<GenericDocument> documents = request.getGenericDocuments(); - List<Bundle> documentBundles = new ArrayList<>(documents.size()); - for (int i = 0; i < documents.size(); i++) { - documentBundles.add(documents.get(i).getBundle()); - } - AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>(); - try { - mService.putDocuments( - getPackageName(), - DEFAULT_DATABASE_NAME, - documentBundles, - mContext.getUserId(), - new IAppSearchBatchResultCallback.Stub() { - public void onResult(AppSearchBatchResult result) { - future.complete(result); - } - - public void onSystemError(ParcelableException exception) { - future.completeExceptionally(exception); - } - }); - } catch (RemoteException e) { - future.completeExceptionally(e); - } - return getFutureOrThrow(future); - } - - /** - * Retrieves {@link GenericDocument}s by URI. - * - * <p>You should not call this method directly; instead, use the {@code - * AppSearch#getDocuments()} API provided by JetPack. - * - * @param request {@link GetByUriRequest} containing URIs to be retrieved. - * @return The pending result of performing this operation. The keys of the returned {@link - * AppSearchBatchResult} are the input URIs. The values are the returned {@link - * GenericDocument}s on success, or a failed {@link AppSearchResult} otherwise. URIs that - * are not found will return a failed {@link AppSearchResult} with a result code of {@link - * AppSearchResult#RESULT_NOT_FOUND}. - * @throws RuntimeException If an error occurred during the execution. - * @hide - * @deprecated use {@link AppSearchSession#getByUri} instead. - */ - public AppSearchBatchResult<String, GenericDocument> getByUri( - @NonNull GetByUriRequest request) { - // TODO(b/146386470): Transmit the result documents as a RemoteStream instead of sending - // them in one big list. - List<String> uris = new ArrayList<>(request.getUris()); - AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>(); - try { - mService.getDocuments( - getPackageName(), - DEFAULT_DATABASE_NAME, - request.getNamespace(), - uris, - request.getProjectionsInternal(), - mContext.getUserId(), - new IAppSearchBatchResultCallback.Stub() { - public void onResult(AppSearchBatchResult result) { - future.complete(result); - } - - public void onSystemError(ParcelableException exception) { - future.completeExceptionally(exception); - } - }); - } catch (RemoteException e) { - future.completeExceptionally(e); - } - - // Translate from document bundles to GenericDocument instances - AppSearchBatchResult<String, Bundle> bundleResult = getFutureOrThrow(future); - AppSearchBatchResult.Builder<String, GenericDocument> documentResultBuilder = - new AppSearchBatchResult.Builder<>(); - - // Translate successful results - for (Map.Entry<String, Bundle> bundleEntry : bundleResult.getSuccesses().entrySet()) { - GenericDocument document; - try { - document = new GenericDocument(bundleEntry.getValue()); - } catch (Throwable t) { - // These documents went through validation, so how could this fail? We must have - // done something wrong. - documentResultBuilder.setFailure( - bundleEntry.getKey(), - AppSearchResult.RESULT_INTERNAL_ERROR, - t.getMessage()); - continue; - } - documentResultBuilder.setSuccess(bundleEntry.getKey(), document); - } - - // Translate failed results - for (Map.Entry<String, AppSearchResult<Bundle>> bundleEntry : - bundleResult.getFailures().entrySet()) { - documentResultBuilder.setFailure( - bundleEntry.getKey(), - bundleEntry.getValue().getResultCode(), - bundleEntry.getValue().getErrorMessage()); - } - - return documentResultBuilder.build(); - } - - /** - * Searches a document based on a given query string. - * - * <p>You should not call this method directly; instead, use the {@code AppSearch#query()} API - * provided by JetPack. - * - * <p>Currently we support following features in the raw query format: - * - * <ul> - * <li>AND - * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and ‘cat’”). - * Example: hello world matches documents that have both ‘hello’ and ‘world’ - * <li>OR - * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or ‘cat’”). Example: - * dog OR puppy - * <li>Exclusion - * <p>Exclude a term (e.g. “match documents that do not have the term ‘dog’”). Example: - * -dog excludes the term ‘dog’ - * <li>Grouping terms - * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g. - * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”). - * Example: (dog puppy) (cat kitten) two one group containing two terms. - * <li>Property restricts - * <p>Specifies which properties of a document to specifically match terms in (e.g. “match - * documents where the ‘subject’ property contains ‘important’”). Example: - * subject:important matches documents with the term ‘important’ in the ‘subject’ property - * <li>Schema type restricts - * <p>This is similar to property restricts, but allows for restricts on top-level - * document fields, such as schema_type. Clients should be able to limit their query to - * documents of a certain schema_type (e.g. “match documents that are of the ‘Email’ - * schema_type”). Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will - * match documents that contain the query term ‘dog’ and are of either the ‘Email’ schema - * type or the ‘Video’ schema type. - * </ul> - * - * @param queryExpression Query String to search. - * @param searchSpec Spec for setting filters, raw query etc. - * @throws RuntimeException If an error occurred during the execution. - * @hide - * @deprecated use AppSearchSession#query instead. - */ - @NonNull - public AppSearchResult<List<SearchResult>> query( - @NonNull String queryExpression, @NonNull SearchSpec searchSpec) { - // TODO(b/146386470): Transmit the result documents as a RemoteStream instead of sending - // them in one big list. - AndroidFuture<AppSearchResult> future = new AndroidFuture<>(); - try { - mService.query( - getPackageName(), - DEFAULT_DATABASE_NAME, - queryExpression, - searchSpec.getBundle(), - mContext.getUserId(), - new IAppSearchResultCallback.Stub() { - public void onResult(AppSearchResult result) { - future.complete(result); - } - }); - AppSearchResult<Bundle> bundleResult = getFutureOrThrow(future); - if (!bundleResult.isSuccess()) { - return AppSearchResult.newFailedResult( - bundleResult.getResultCode(), bundleResult.getErrorMessage()); - } - SearchResultPage searchResultPage = new SearchResultPage(bundleResult.getResultValue()); - return AppSearchResult.newSuccessfulResult(searchResultPage.getResults()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } catch (Throwable t) { - return AppSearchResult.throwableToFailedResult(t); - } - } - - /** - * Removes {@link GenericDocument}s by URI. - * - * <p>You should not call this method directly; instead, use the {@code AppSearch#delete()} API - * provided by JetPack. - * - * @param request Request containing URIs to be removed. - * @return The pending result of performing this operation. The keys of the returned {@link - * AppSearchBatchResult} are the input URIs. The values are {@code null} on success, or a - * failed {@link AppSearchResult} otherwise. URIs that are not found will return a failed - * {@link AppSearchResult} with a result code of {@link AppSearchResult#RESULT_NOT_FOUND}. - * @throws RuntimeException If an error occurred during the execution. - * @hide - * @deprecated use {@link AppSearchSession#remove} instead. - */ - public AppSearchBatchResult<String, Void> removeByUri(@NonNull RemoveByUriRequest request) { - List<String> uris = new ArrayList<>(request.getUris()); - AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>(); - try { - mService.removeByUri( - getPackageName(), - DEFAULT_DATABASE_NAME, - request.getNamespace(), - uris, - mContext.getUserId(), - new IAppSearchBatchResultCallback.Stub() { - public void onResult(AppSearchBatchResult result) { - future.complete(result); - } - - public void onSystemError(ParcelableException exception) { - future.completeExceptionally(exception); - } - }); - } catch (RemoteException e) { - future.completeExceptionally(e); - } - return getFutureOrThrow(future); - } - /** Returns the package name that should be used for uid verification. */ @NonNull private String getPackageName() { return mContext.getOpPackageName(); } - - private static <T> T getFutureOrThrow(@NonNull AndroidFuture<T> future) { - try { - return future.get(); - } catch (Throwable e) { - if (e instanceof ExecutionException) { - e = e.getCause(); - } - if (e instanceof RuntimeException) { - throw (RuntimeException) e; - } - if (e instanceof Error) { - throw (Error) e; - } - throw new RuntimeException(e); - } - } } diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java index 4b0f719b13be..999860fdf4da 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java @@ -42,7 +42,7 @@ public class BlobStoreIdleJobService extends JobService { blobStoreManagerInternal.onIdleMaintenance(); jobFinished(params, false); }); - return false; + return true; } @Override diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java index b7a3f1083176..6967d819a448 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java @@ -59,6 +59,9 @@ import java.util.Objects; * constraint on the JobInfo object that you are creating. Otherwise, the builder would throw an * exception when building. From Android version {@link Build.VERSION_CODES#Q} and onwards, it is * valid to schedule jobs with no constraints. + * <p> Prior to Android version {@link Build.VERSION_CODES#S}, jobs could only have a maximum of 100 + * jobs scheduled at a time. Starting with Android version {@link Build.VERSION_CODES#S}, that limit + * has been increased to 150. Expedited jobs also count towards the limit. * <p> In Android version {@link Build.VERSION_CODES#LOLLIPOP}, jobs had a maximum execution time * of one minute. Starting with Android version {@link Build.VERSION_CODES#M} and ending with * Android version {@link Build.VERSION_CODES#R}, jobs had a maximum execution time of 10 minutes. diff --git a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java index 0c4fcb4ec1b0..6e4a5a0c5784 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java @@ -22,6 +22,7 @@ import android.app.SystemServiceRegistry; import android.content.Context; import android.os.DeviceIdleManager; import android.os.IDeviceIdleController; +import android.os.PowerExemptionManager; import android.os.PowerWhitelistManager; /** @@ -52,5 +53,8 @@ public class JobSchedulerFrameworkInitializer { SystemServiceRegistry.registerContextAwareService( Context.POWER_WHITELIST_MANAGER, PowerWhitelistManager.class, PowerWhitelistManager::new); + SystemServiceRegistry.registerContextAwareService( + Context.POWER_EXEMPTION_SERVICE, PowerExemptionManager.class, + PowerExemptionManager::new); } } diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java new file mode 100644 index 000000000000..8445335b568e --- /dev/null +++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; +import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; +import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; +import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT; +import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI; +import static android.app.ActivityManager.PROCESS_STATE_TOP; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.content.Context; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Collections; +import java.util.List; + +/** + * Interface to access and modify the permanent and temporary power save allow list. The two lists + * are kept separately. Apps placed on the permanent allow list are only removed via an explicit + * {@link #removeFromAllowList(String)} call. Apps allow-listed by default by the system cannot be + * removed. Apps placed on the temporary allow list are removed from that allow list after a + * predetermined amount of time. + * + * @hide + */ +@SystemApi +@SystemService(Context.POWER_EXEMPTION_SERVICE) +public class PowerExemptionManager { + private final Context mContext; + // Proxy to DeviceIdleController for now + // TODO: migrate to PowerExemptionController + private final IDeviceIdleController mService; + + /** + * Indicates that an unforeseen event has occurred and the app should be allow-listed to handle + * it. + */ + public static final int EVENT_UNSPECIFIED = 0; + + /** + * Indicates that an SMS event has occurred and the app should be allow-listed to handle it. + */ + public static final int EVENT_SMS = 1; + + /** + * Indicates that an MMS event has occurred and the app should be allow-listed to handle it. + */ + public static final int EVENT_MMS = 2; + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"EVENT_"}, value = { + EVENT_UNSPECIFIED, + EVENT_SMS, + EVENT_MMS, + }) + public @interface AllowListEvent { + } + + /** + * Allow the temp allow list behavior, plus allow foreground service start from background. + */ + public static final int TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; + /** + * Only allow the temp allow list behavior, not allow foreground service start from background. + */ + public static final int TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; + + /** + * The list of temp allow list types. + * @hide + */ + @IntDef(flag = true, prefix = { "TEMPORARY_ALLOW_LIST_TYPE_" }, value = { + TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, + TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface TempAllowListType {} + + /* Reason codes for BG-FGS-launch. */ + /** + * BG-FGS-launch is denied. + * @hide + */ + public static final int REASON_DENIED = -1; + + /* Reason code range 0-9 are reserved for default reasons */ + /** + * The default reason code if reason is unknown. + */ + public static final int REASON_UNKNOWN = 0; + /** + * Use REASON_OTHER if there is no better choice. + */ + public static final int REASON_OTHER = 1; + + /* Reason code range 10-49 are reserved for BG-FGS-launch allowed proc states */ + /** @hide */ + public static final int REASON_PROC_STATE_PERSISTENT = 10; + /** @hide */ + public static final int REASON_PROC_STATE_PERSISTENT_UI = 11; + /** @hide */ + public static final int REASON_PROC_STATE_TOP = 12; + /** @hide */ + public static final int REASON_PROC_STATE_BTOP = 13; + /** @hide */ + public static final int REASON_PROC_STATE_FGS = 14; + /** @hide */ + public static final int REASON_PROC_STATE_BFGS = 15; + + /* Reason code range 50-99 are reserved for BG-FGS-launch allowed reasons */ + /** @hide */ + public static final int REASON_UID_VISIBLE = 50; + /** @hide */ + public static final int REASON_SYSTEM_UID = 51; + /** @hide */ + public static final int REASON_ACTIVITY_STARTER = 52; + /** @hide */ + public static final int REASON_START_ACTIVITY_FLAG = 53; + /** @hide */ + public static final int REASON_FGS_BINDING = 54; + /** @hide */ + public static final int REASON_DEVICE_OWNER = 55; + /** @hide */ + public static final int REASON_PROFILE_OWNER = 56; + /** @hide */ + public static final int REASON_COMPANION_DEVICE_MANAGER = 57; + /** + * START_ACTIVITIES_FROM_BACKGROUND permission. + * @hide + */ + public static final int REASON_BACKGROUND_ACTIVITY_PERMISSION = 58; + /** + * START_FOREGROUND_SERVICES_FROM_BACKGROUND permission. + * @hide + */ + public static final int REASON_BACKGROUND_FGS_PERMISSION = 59; + /** @hide */ + public static final int REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION = 60; + /** @hide */ + public static final int REASON_INSTR_BACKGROUND_FGS_PERMISSION = 61; + /** @hide */ + public static final int REASON_SYSTEM_ALERT_WINDOW_PERMISSION = 62; + /** @hide */ + public static final int REASON_DEVICE_DEMO_MODE = 63; + /** @hide */ + public static final int REASON_EXEMPTED_PACKAGE = 64; + /** @hide */ + public static final int REASON_ALLOWLISTED_PACKAGE = 65; + /** @hide */ + public static final int REASON_APPOP = 66; + + /* BG-FGS-launch is allowed by temp-allow-list or system-allow-list. + Reason code for temp and system allow list starts here. + Reason code range 100-199 are reserved for public reasons. */ + /** + * Set temp-allow-list for location geofence purpose. + */ + public static final int REASON_GEOFENCING = 100; + /** + * Set temp-allow-list for server push messaging. + */ + public static final int REASON_PUSH_MESSAGING = 101; + /** + * Set temp-allow-list for server push messaging over the quota. + */ + public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102; + /** + * Set temp-allow-list for activity recognition. + */ + public static final int REASON_ACTIVITY_RECOGNITION = 103; + + /* Reason code range 200-299 are reserved for broadcast actions */ + /** + * Broadcast ACTION_BOOT_COMPLETED. + * @hide + */ + public static final int REASON_BOOT_COMPLETED = 200; + /** + * Broadcast ACTION_PRE_BOOT_COMPLETED. + * @hide + */ + public static final int REASON_PRE_BOOT_COMPLETED = 201; + /** + * Broadcast ACTION_LOCKED_BOOT_COMPLETED. + * @hide + */ + public static final int REASON_LOCKED_BOOT_COMPLETED = 202; + + /* Reason code range 300-399 are reserved for other internal reasons */ + /** + * Device idle system allow list, including EXCEPT-IDLE + * @hide + */ + public static final int REASON_SYSTEM_ALLOW_LISTED = 300; + /** @hide */ + public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 301; + /** + * AlarmManagerService. + * @hide + */ + public static final int REASON_ALARM_MANAGER_WHILE_IDLE = 302; + /** + * ActiveServices. + * @hide + */ + public static final int REASON_SERVICE_LAUNCH = 303; + /** + * KeyChainSystemService. + * @hide + */ + public static final int REASON_KEY_CHAIN = 304; + /** + * PackageManagerService. + * @hide + */ + public static final int REASON_PACKAGE_VERIFIER = 305; + /** + * SyncManager. + * @hide + */ + public static final int REASON_SYNC_MANAGER = 306; + /** + * DomainVerificationProxyV1. + * @hide + */ + public static final int REASON_DOMAIN_VERIFICATION_V1 = 307; + /** + * DomainVerificationProxyV2. + * @hide + */ + public static final int REASON_DOMAIN_VERIFICATION_V2 = 308; + /** @hide */ + public static final int REASON_VPN = 309; + /** + * NotificationManagerService. + * @hide + */ + public static final int REASON_NOTIFICATION_SERVICE = 310; + /** + * Broadcast ACTION_MY_PACKAGE_REPLACED. + * @hide + */ + public static final int REASON_PACKAGE_REPLACED = 311; + /** + * LocationProviderManager. + * @hide + */ + public static final int REASON_LOCATION_PROVIDER = 312; + /** + * MediaButtonReceiver. + * @hide + */ + public static final int REASON_MEDIA_BUTTON = 313; + /** + * InboundSmsHandler. + * @hide + */ + public static final int REASON_EVENT_SMS = 314; + /** + * InboundSmsHandler. + * @hide + */ + public static final int REASON_EVENT_MMS = 315; + /** + * Shell app. + * @hide + */ + public static final int REASON_SHELL = 316; + + /** + * The list of BG-FGS-Launch and temp-allow-list reason code. + * @hide + */ + @IntDef(flag = true, prefix = { "REASON_" }, value = { + // BG-FGS-Launch reasons. + REASON_DENIED, + REASON_UNKNOWN, + REASON_OTHER, + REASON_PROC_STATE_PERSISTENT, + REASON_PROC_STATE_PERSISTENT_UI, + REASON_PROC_STATE_TOP, + REASON_PROC_STATE_BTOP, + REASON_PROC_STATE_FGS, + REASON_PROC_STATE_BFGS, + REASON_UID_VISIBLE, + REASON_SYSTEM_UID, + REASON_ACTIVITY_STARTER, + REASON_START_ACTIVITY_FLAG, + REASON_FGS_BINDING, + REASON_DEVICE_OWNER, + REASON_PROFILE_OWNER, + REASON_COMPANION_DEVICE_MANAGER, + REASON_BACKGROUND_ACTIVITY_PERMISSION, + REASON_BACKGROUND_FGS_PERMISSION, + REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION, + REASON_INSTR_BACKGROUND_FGS_PERMISSION, + REASON_SYSTEM_ALERT_WINDOW_PERMISSION, + REASON_DEVICE_DEMO_MODE, + REASON_EXEMPTED_PACKAGE, + REASON_ALLOWLISTED_PACKAGE, + REASON_APPOP, + // temp and system allow list reasons. + REASON_GEOFENCING, + REASON_PUSH_MESSAGING, + REASON_PUSH_MESSAGING_OVER_QUOTA, + REASON_ACTIVITY_RECOGNITION, + REASON_BOOT_COMPLETED, + REASON_PRE_BOOT_COMPLETED, + REASON_LOCKED_BOOT_COMPLETED, + REASON_SYSTEM_ALLOW_LISTED, + REASON_ALARM_MANAGER_ALARM_CLOCK, + REASON_ALARM_MANAGER_WHILE_IDLE, + REASON_SERVICE_LAUNCH, + REASON_KEY_CHAIN, + REASON_PACKAGE_VERIFIER, + REASON_SYNC_MANAGER, + REASON_DOMAIN_VERIFICATION_V1, + REASON_DOMAIN_VERIFICATION_V2, + REASON_VPN, + REASON_NOTIFICATION_SERVICE, + REASON_PACKAGE_REPLACED, + REASON_LOCATION_PROVIDER, + REASON_MEDIA_BUTTON, + REASON_EVENT_SMS, + REASON_EVENT_MMS, + REASON_SHELL, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ReasonCode {} + + /** + * @hide + */ + public PowerExemptionManager(@NonNull Context context) { + mContext = context; + mService = context.getSystemService(DeviceIdleManager.class).getService(); + } + + /** + * Add the specified package to the permanent power save allow list. + */ + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + public void addToPermanentAllowList(@NonNull String packageName) { + addToPermanentAllowList(Collections.singletonList(packageName)); + } + + /** + * Add the specified packages to the permanent power save allow list. + */ + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + public void addToPermanentAllowList(@NonNull List<String> packageNames) { + try { + mService.addPowerSaveWhitelistApps(packageNames); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get a list of app IDs of app that are allow-listed. This does not include temporarily + * allow-listed apps. + * + * @param includingIdle Set to true if the app should be allow-listed from device idle as well + * as other power save restrictions + * @hide + */ + @NonNull + public int[] getAllowListedAppIds(boolean includingIdle) { + try { + if (includingIdle) { + return mService.getAppIdWhitelist(); + } else { + return mService.getAppIdWhitelistExceptIdle(); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns true if the app is allow-listed from power save restrictions. This does not include + * temporarily allow-listed apps. + * + * @param includingIdle Set to true if the app should be allow-listed from device + * idle as well as other power save restrictions + * @hide + */ + public boolean isAllowListed(@NonNull String packageName, boolean includingIdle) { + try { + if (includingIdle) { + return mService.isPowerSaveWhitelistApp(packageName); + } else { + return mService.isPowerSaveWhitelistExceptIdleApp(packageName); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Remove an app from the permanent power save allow list. Only apps that were added via + * {@link #addToPermanentAllowList(String)} or {@link #addToPermanentAllowList(List)} will be + * removed. Apps allow-listed by default by the system cannot be removed. + * + * @param packageName The app to remove from the allow list + */ + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + public void removeFromAllowList(@NonNull String packageName) { + try { + mService.removePowerSaveWhitelistApp(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Add an app to the temporary allow list for a short amount of time. + * + * @param packageName The package to add to the temp allow list + * @param durationMs How long to keep the app on the temp allow list for (in milliseconds) + * @param reasonCode one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure. + * @param reason a optional human readable reason string, could be null or empty string. + */ + @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) + public void addToTemporaryAllowList(@NonNull String packageName, long durationMs, + @ReasonCode int reasonCode, @Nullable String reason) { + try { + mService.addPowerSaveTempWhitelistApp(packageName, durationMs, mContext.getUserId(), + reasonCode, reason); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Add an app to the temporary allow list for a short amount of time for a specific reason. + * The temporary allow list is kept separately from the permanent allow list and apps are + * automatically removed from the temporary allow list after a predetermined amount of time. + * + * @param packageName The package to add to the temp allow list + * @param event The reason to add the app to the temp allow list + * @param reasonCode one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure. + * @param reason A human-readable reason explaining why the app is temp allow-listed. Only + * used for logging purposes. Could be null or empty string. + * @return The duration (in milliseconds) that the app is allow-listed for + */ + @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) + public long addToTemporaryAllowListForEvent(@NonNull String packageName, + @AllowListEvent int event, @ReasonCode int reasonCode, @Nullable String reason) { + try { + switch (event) { + case EVENT_MMS: + return mService.addPowerSaveTempWhitelistAppForMms( + packageName, mContext.getUserId(), reasonCode, reason); + case EVENT_SMS: + return mService.addPowerSaveTempWhitelistAppForSms( + packageName, mContext.getUserId(), reasonCode, reason); + case EVENT_UNSPECIFIED: + default: + return mService.whitelistAppTemporarily( + packageName, mContext.getUserId(), reasonCode, reason); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public static @ReasonCode int getReasonCodeFromProcState(int procState) { + if (procState <= PROCESS_STATE_PERSISTENT) { + return REASON_PROC_STATE_PERSISTENT; + } else if (procState <= PROCESS_STATE_PERSISTENT_UI) { + return REASON_PROC_STATE_PERSISTENT_UI; + } else if (procState <= PROCESS_STATE_TOP) { + return REASON_PROC_STATE_TOP; + } else if (procState <= PROCESS_STATE_BOUND_TOP) { + return REASON_PROC_STATE_BTOP; + } else if (procState <= PROCESS_STATE_FOREGROUND_SERVICE) { + return REASON_PROC_STATE_FGS; + } else if (procState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { + return REASON_PROC_STATE_BFGS; + } else { + return REASON_DENIED; + } + } + + /** + * Return string name of the integer reason code. + * @hide + * @param reasonCode + * @return string name of the reason code. + */ + public static String reasonCodeToString(@ReasonCode int reasonCode) { + switch (reasonCode) { + case REASON_DENIED: + return "DENIED"; + case REASON_UNKNOWN: + return "UNKNOWN"; + case REASON_OTHER: + return "OTHER"; + case REASON_PROC_STATE_PERSISTENT: + return "PROC_STATE_PERSISTENT"; + case REASON_PROC_STATE_PERSISTENT_UI: + return "PROC_STATE_PERSISTENT_UI"; + case REASON_PROC_STATE_TOP: + return "PROC_STATE_TOP"; + case REASON_PROC_STATE_BTOP: + return "PROC_STATE_BTOP"; + case REASON_PROC_STATE_FGS: + return "PROC_STATE_FGS"; + case REASON_PROC_STATE_BFGS: + return "PROC_STATE_BFGS"; + case REASON_UID_VISIBLE: + return "UID_VISIBLE"; + case REASON_SYSTEM_UID: + return "SYSTEM_UID"; + case REASON_ACTIVITY_STARTER: + return "ACTIVITY_STARTER"; + case REASON_START_ACTIVITY_FLAG: + return "START_ACTIVITY_FLAG"; + case REASON_FGS_BINDING: + return "FGS_BINDING"; + case REASON_DEVICE_OWNER: + return "DEVICE_OWNER"; + case REASON_PROFILE_OWNER: + return "PROFILE_OWNER"; + case REASON_COMPANION_DEVICE_MANAGER: + return "COMPANION_DEVICE_MANAGER"; + case REASON_BACKGROUND_ACTIVITY_PERMISSION: + return "BACKGROUND_ACTIVITY_PERMISSION"; + case REASON_BACKGROUND_FGS_PERMISSION: + return "BACKGROUND_FGS_PERMISSION"; + case REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION: + return "INSTR_BACKGROUND_ACTIVITY_PERMISSION"; + case REASON_INSTR_BACKGROUND_FGS_PERMISSION: + return "INSTR_BACKGROUND_FGS_PERMISSION"; + case REASON_SYSTEM_ALERT_WINDOW_PERMISSION: + return "SYSTEM_ALERT_WINDOW_PERMISSION"; + case REASON_DEVICE_DEMO_MODE: + return "DEVICE_DEMO_MODE"; + case REASON_EXEMPTED_PACKAGE: + return "EXEMPTED_PACKAGE"; + case REASON_ALLOWLISTED_PACKAGE: + return "ALLOWLISTED_PACKAGE"; + case REASON_APPOP: + return "APPOP"; + case REASON_GEOFENCING: + return "GEOFENCING"; + case REASON_PUSH_MESSAGING: + return "PUSH_MESSAGING"; + case REASON_PUSH_MESSAGING_OVER_QUOTA: + return "PUSH_MESSAGING_OVER_QUOTA"; + case REASON_ACTIVITY_RECOGNITION: + return "ACTIVITY_RECOGNITION"; + case REASON_BOOT_COMPLETED: + return "BOOT_COMPLETED"; + case REASON_PRE_BOOT_COMPLETED: + return "PRE_BOOT_COMPLETED"; + case REASON_LOCKED_BOOT_COMPLETED: + return "LOCKED_BOOT_COMPLETED"; + case REASON_SYSTEM_ALLOW_LISTED: + return "SYSTEM_ALLOW_LISTED"; + case REASON_ALARM_MANAGER_ALARM_CLOCK: + return "ALARM_MANAGER_ALARM_CLOCK"; + case REASON_ALARM_MANAGER_WHILE_IDLE: + return "ALARM_MANAGER_WHILE_IDLE"; + case REASON_SERVICE_LAUNCH: + return "SERVICE_LAUNCH"; + case REASON_KEY_CHAIN: + return "KEY_CHAIN"; + case REASON_PACKAGE_VERIFIER: + return "PACKAGE_VERIFIER"; + case REASON_SYNC_MANAGER: + return "SYNC_MANAGER"; + case REASON_DOMAIN_VERIFICATION_V1: + return "DOMAIN_VERIFICATION_V1"; + case REASON_DOMAIN_VERIFICATION_V2: + return "DOMAIN_VERIFICATION_V2"; + case REASON_VPN: + return "VPN"; + case REASON_NOTIFICATION_SERVICE: + return "NOTIFICATION_SERVICE"; + case REASON_PACKAGE_REPLACED: + return "PACKAGE_REPLACED"; + case REASON_LOCATION_PROVIDER: + return "LOCATION_PROVIDER"; + case REASON_MEDIA_BUTTON: + return "MEDIA_BUTTON"; + case REASON_EVENT_SMS: + return "EVENT_SMS"; + case REASON_EVENT_MMS: + return "EVENT_MMS"; + case REASON_SHELL: + return "SHELL"; + default: + return "(unknown:" + reasonCode + ")"; + } + } +} diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 515cb747a99e..82f2f69bbde5 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -147,10 +147,8 @@ public class JobSchedulerService extends com.android.server.SystemService /** The maximum number of concurrent jobs we run at one time. */ static final int MAX_JOB_CONTEXTS_COUNT = 16; - /** Enforce a per-app limit on scheduled jobs? */ - private static final boolean ENFORCE_MAX_JOBS = true; - /** The maximum number of jobs that we allow an unprivileged app to schedule */ - private static final int MAX_JOBS_PER_APP = 100; + /** The maximum number of jobs that we allow an app to schedule */ + private static final int MAX_JOBS_PER_APP = 150; /** The number of the most recently completed jobs to keep track of for debugging purposes. */ private static final int NUM_COMPLETED_JOB_HISTORY = 20; @@ -1011,7 +1009,7 @@ public class JobSchedulerService extends com.android.server.SystemService if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString()); // Jobs on behalf of others don't apply to the per-app job cap - if (ENFORCE_MAX_JOBS && packageName == null) { + if (packageName == null) { if (mJobs.countJobsForUid(uId) > MAX_JOBS_PER_APP) { Slog.w(TAG, "Too many jobs for uid " + uId); throw new IllegalStateException("Apps may not schedule more than " diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt index af2d2f75b823..6158e2ece55f 100644 --- a/apex/media/framework/api/system-current.txt +++ b/apex/media/framework/api/system-current.txt @@ -47,12 +47,16 @@ package android.media { public static final class MediaTranscodeManager.TranscodingSession { method public void cancel(); + method public int getErrorCode(); method @IntRange(from=0, to=100) public int getProgress(); method public int getResult(); method public int getSessionId(); method public int getStatus(); method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener); method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener); + field public static final int ERROR_DROPPED_BY_SERVICE = 1; // 0x1 + field public static final int ERROR_NONE = 0; // 0x0 + field public static final int ERROR_SERVICE_DIED = 2; // 0x2 field public static final int RESULT_CANCELED = 4; // 0x4 field public static final int RESULT_ERROR = 3; // 0x3 field public static final int RESULT_NONE = 1; // 0x1 diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java index b29bed978a21..30d1896a23ac 100644 --- a/apex/media/framework/java/android/media/MediaTranscodeManager.java +++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java @@ -217,7 +217,8 @@ public final class MediaTranscodeManager { // Updates the session status and result. session.updateStatusAndResult(TranscodingSession.STATUS_FINISHED, - TranscodingSession.RESULT_SUCCESS); + TranscodingSession.RESULT_SUCCESS, + TranscodingSession.ERROR_NONE); // Notifies client the session is done. if (session.mListener != null && session.mListenerExecutor != null) { @@ -241,7 +242,7 @@ public final class MediaTranscodeManager { // Updates the session status and result. session.updateStatusAndResult(TranscodingSession.STATUS_FINISHED, - TranscodingSession.RESULT_ERROR); + TranscodingSession.RESULT_ERROR, errorCode); // Notifies client the session failed. if (session.mListener != null && session.mListenerExecutor != null) { @@ -330,7 +331,8 @@ public final class MediaTranscodeManager { if (session.getStatus() == TranscodingSession.STATUS_RUNNING) { session.updateStatusAndResult(TranscodingSession.STATUS_FINISHED, - TranscodingSession.RESULT_ERROR); + TranscodingSession.RESULT_ERROR, + TranscodingSession.ERROR_SERVICE_DIED); // Remove the session from pending sessions. mPendingTranscodingSessions.remove(entry.getKey()); @@ -1239,6 +1241,33 @@ public final class MediaTranscodeManager { @Retention(RetentionPolicy.SOURCE) public @interface Result {} + + // The error code exposed here should be in sync with: + // frameworks/av/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl + /** @hide */ + @IntDef(prefix = { "TRANSCODING_SESSION_ERROR_" }, value = { + ERROR_NONE, + ERROR_DROPPED_BY_SERVICE, + ERROR_SERVICE_DIED}) + @Retention(RetentionPolicy.SOURCE) + public @interface TranscodingSessionErrorCode{} + /** + * Constant indicating that no error occurred. + */ + public static final int ERROR_NONE = 0; + + /** + * Constant indicating that the session is dropped by Transcoding service due to hitting + * the limit, e.g. too many back to back transcoding happen in a short time frame. + */ + public static final int ERROR_DROPPED_BY_SERVICE = 1; + + /** + * Constant indicating the backing transcoding service is died. Client should enqueue the + * the request again. + */ + public static final int ERROR_SERVICE_DIED = 2; + /** Listener that gets notified when the progress changes. */ @FunctionalInterface public interface OnProgressUpdateListener { @@ -1272,6 +1301,8 @@ public final class MediaTranscodeManager { @GuardedBy("mLock") private @Result int mResult = RESULT_NONE; @GuardedBy("mLock") + private @TranscodingSessionErrorCode int mErrorCode = ERROR_NONE; + @GuardedBy("mLock") private boolean mHasRetried = false; // The original request that associated with this session. private final TranscodingRequest mRequest; @@ -1325,10 +1356,20 @@ public final class MediaTranscodeManager { } private void updateStatusAndResult(@Status int sessionStatus, - @Result int sessionResult) { + @Result int sessionResult, @TranscodingSessionErrorCode int errorCode) { synchronized (mLock) { mStatus = sessionStatus; mResult = sessionResult; + mErrorCode = errorCode; + } + } + + /** + * Retrieve the error code associated with the RESULT_ERROR. + */ + public @TranscodingSessionErrorCode int getErrorCode() { + synchronized (mLock) { + return mErrorCode; } } diff --git a/api/Android.bp b/api/Android.bp index 1d4698e7c512..1fdf1771bb13 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -347,3 +347,49 @@ genrule { out: ["combined-removed-dex.txt"], cmd: "$(location gen_combined_removed_dex.sh) $(location metalava) $(genDir) $(in) > $(out)", } + +genrule { + name: "services-system-server-current.txt", + srcs: [ + ":service-permission{.system-server.api.txt}", + ":non-updatable-system-server-current.txt", + ], + out: ["system-server-current.txt"], + tools: ["metalava"], + cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dists: [ + { + targets: ["droidcore"], + dir: "api", + dest: "system-server-current.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system-server/api", + dest: "merge-android.txt", + }, + ], +} + +genrule { + name: "services-system-server-removed.txt", + srcs: [ + ":service-permission{.system-server.removed-api.txt}", + ":non-updatable-system-server-removed.txt", + ], + out: ["system-server-removed.txt"], + tools: ["metalava"], + cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dists: [ + { + targets: ["droidcore"], + dir: "api", + dest: "system-server-removed.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system-server/api", + dest: "merge-removed.txt", + }, + ], +} diff --git a/config/preloaded-classes b/config/preloaded-classes index c6ec37690d88..7c3fd8ce8aea 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -1844,11 +1844,9 @@ android.database.sqlite.SqliteWrapper android.ddm.DdmHandleAppName$Names android.ddm.DdmHandleAppName android.ddm.DdmHandleExit -android.ddm.DdmHandleHeap android.ddm.DdmHandleHello android.ddm.DdmHandleNativeHeap android.ddm.DdmHandleProfiling -android.ddm.DdmHandleThread android.ddm.DdmHandleViewDebug android.ddm.DdmRegister android.debug.AdbManager diff --git a/core/api/current.txt b/core/api/current.txt index 2e0282a8d7a4..829bb3fcf328 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -329,6 +329,7 @@ package android { field public static final int apiKey = 16843281; // 0x1010211 field public static final int appCategory = 16844101; // 0x1010545 field public static final int appComponentFactory = 16844154; // 0x101057a + field public static final int attributionTags = 16844353; // 0x1010641 field public static final int author = 16843444; // 0x10102b4 field public static final int authorities = 16842776; // 0x1010018 field public static final int autoAdvanceViewId = 16843535; // 0x101030f @@ -506,7 +507,7 @@ package android { field public static final int dashGap = 16843175; // 0x10101a7 field public static final int dashWidth = 16843174; // 0x10101a6 field public static final int data = 16842798; // 0x101002e - field public static final int dataExtractionRules = 16844350; // 0x101063e + field public static final int dataExtractionRules = 16844349; // 0x101063d field public static final int datePickerDialogTheme = 16843948; // 0x10104ac field public static final int datePickerMode = 16843955; // 0x10104b3 field public static final int datePickerStyle = 16843612; // 0x101035c @@ -528,8 +529,8 @@ package android { field public static final int detailSocialSummary = 16843428; // 0x10102a4 field public static final int detailsElementBackground = 16843598; // 0x101034e field public static final int dial = 16843010; // 0x1010102 - field public static final int dialTint = 16844342; // 0x1010636 - field public static final int dialTintMode = 16844343; // 0x1010637 + field public static final int dialTint = 16844341; // 0x1010635 + field public static final int dialTintMode = 16844342; // 0x1010636 field public static final int dialogCornerRadius = 16844145; // 0x1010571 field public static final int dialogIcon = 16843252; // 0x10101f4 field public static final int dialogLayout = 16843255; // 0x10101f7 @@ -727,14 +728,14 @@ package android { field public static final int groupIndicator = 16843019; // 0x101010b field public static final int gwpAsanMode = 16844310; // 0x1010616 field public static final int hand_hour = 16843011; // 0x1010103 - field public static final int hand_hourTint = 16844344; // 0x1010638 - field public static final int hand_hourTintMode = 16844345; // 0x1010639 + field public static final int hand_hourTint = 16844343; // 0x1010637 + field public static final int hand_hourTintMode = 16844344; // 0x1010638 field public static final int hand_minute = 16843012; // 0x1010104 - field public static final int hand_minuteTint = 16844346; // 0x101063a - field public static final int hand_minuteTintMode = 16844347; // 0x101063b + field public static final int hand_minuteTint = 16844345; // 0x1010639 + field public static final int hand_minuteTintMode = 16844346; // 0x101063a field public static final int hand_second = 16844323; // 0x1010623 - field public static final int hand_secondTint = 16844348; // 0x101063c - field public static final int hand_secondTintMode = 16844349; // 0x101063d + field public static final int hand_secondTint = 16844347; // 0x101063b + field public static final int hand_secondTintMode = 16844348; // 0x101063c field public static final int handle = 16843354; // 0x101025a field public static final int handleProfiling = 16842786; // 0x1010022 field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e @@ -818,7 +819,7 @@ package android { field public static final int installLocation = 16843447; // 0x10102b7 field public static final int interactiveUiTimeout = 16844181; // 0x1010595 field public static final int interpolator = 16843073; // 0x1010141 - field public static final int isAccessibilityTool = 16844353; // 0x1010641 + field public static final int isAccessibilityTool = 16844352; // 0x1010640 field public static final int isAlwaysSyncable = 16843571; // 0x1010333 field public static final int isAsciiCapable = 16843753; // 0x10103e9 field public static final int isAuxiliary = 16843647; // 0x101037f @@ -970,8 +971,8 @@ package android { field public static final int maxLines = 16843091; // 0x1010153 field public static final int maxLongVersionCode = 16844163; // 0x1010583 field public static final int maxRecents = 16843846; // 0x1010446 - field public static final int maxResizeHeight = 16844339; // 0x1010633 - field public static final int maxResizeWidth = 16844338; // 0x1010632 + field public static final int maxResizeHeight = 16844338; // 0x1010632 + field public static final int maxResizeWidth = 16844337; // 0x1010631 field public static final int maxRows = 16843059; // 0x1010133 field public static final int maxSdkVersion = 16843377; // 0x1010271 field public static final int maxWidth = 16843039; // 0x101011f @@ -1074,7 +1075,7 @@ package android { field public static final int panelTextAppearance = 16842850; // 0x1010062 field public static final int parentActivityName = 16843687; // 0x10103a7 field @Deprecated public static final int password = 16843100; // 0x101015c - field public static final int passwordsActivity = 16844351; // 0x101063f + field public static final int passwordsActivity = 16844350; // 0x101063e field public static final int path = 16842794; // 0x101002a field public static final int pathAdvancedPattern = 16844320; // 0x1010620 field public static final int pathData = 16843781; // 0x1010405 @@ -1199,7 +1200,6 @@ package android { field public static final int right = 16843183; // 0x10101af field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093 field public static final int ringtoneType = 16843257; // 0x10101f9 - field public static final int rippleStyle = 16844337; // 0x1010631 field public static final int rollbackDataPolicy = 16844311; // 0x1010617 field public static final int rotation = 16843558; // 0x1010326 field public static final int rotationAnimation = 16844090; // 0x101053a @@ -1261,7 +1261,7 @@ package android { field public static final int segmentedButtonStyle = 16843568; // 0x1010330 field public static final int selectAllOnFocus = 16843102; // 0x101015e field public static final int selectable = 16843238; // 0x10101e6 - field public static final int selectableAsDefault = 16844352; // 0x1010640 + field public static final int selectableAsDefault = 16844351; // 0x101063f field public static final int selectableItemBackground = 16843534; // 0x101030e field public static final int selectableItemBackgroundBorderless = 16843868; // 0x101045c field @Deprecated public static final int selectedDateVerticalBar = 16843591; // 0x1010347 @@ -1408,8 +1408,8 @@ package android { field public static final int tabWidgetStyle = 16842883; // 0x1010083 field public static final int tag = 16842961; // 0x10100d1 field public static final int targetActivity = 16843266; // 0x1010202 - field public static final int targetCellHeight = 16844341; // 0x1010635 - field public static final int targetCellWidth = 16844340; // 0x1010634 + field public static final int targetCellHeight = 16844340; // 0x1010634 + field public static final int targetCellWidth = 16844339; // 0x1010633 field public static final int targetClass = 16842799; // 0x101002f field @Deprecated public static final int targetDescriptions = 16843680; // 0x10103a0 field public static final int targetId = 16843740; // 0x10103dc @@ -3855,7 +3855,7 @@ package android.app { method @Deprecated public void onTabUnselected(android.app.ActionBar.Tab, android.app.FragmentTransaction); } - public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback { + @UiContext public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback { ctor public Activity(); method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams); method public void closeContextMenu(); @@ -4771,9 +4771,9 @@ package android.app { } public class Dialog implements android.content.DialogInterface android.view.KeyEvent.Callback android.view.View.OnCreateContextMenuListener android.view.Window.Callback { - ctor public Dialog(@NonNull android.content.Context); - ctor public Dialog(@NonNull android.content.Context, @StyleRes int); - ctor protected Dialog(@NonNull android.content.Context, boolean, @Nullable android.content.DialogInterface.OnCancelListener); + ctor public Dialog(@NonNull @UiContext android.content.Context); + ctor public Dialog(@NonNull @UiContext android.content.Context, @StyleRes int); + ctor protected Dialog(@NonNull @UiContext android.content.Context, boolean, @Nullable android.content.DialogInterface.OnCancelListener); method public void addContentView(@NonNull android.view.View, @Nullable android.view.ViewGroup.LayoutParams); method public void cancel(); method public void closeOptionsMenu(); @@ -4787,7 +4787,7 @@ package android.app { method public boolean dispatchTrackballEvent(@NonNull android.view.MotionEvent); method public <T extends android.view.View> T findViewById(@IdRes int); method @Nullable public android.app.ActionBar getActionBar(); - method @NonNull public final android.content.Context getContext(); + method @NonNull @UiContext public final android.content.Context getContext(); method @Nullable public android.view.View getCurrentFocus(); method @NonNull public android.view.LayoutInflater getLayoutInflater(); method @Nullable public final android.app.Activity getOwnerActivity(); @@ -10346,10 +10346,10 @@ package android.content { method @NonNull public android.content.Context createContext(@NonNull android.content.ContextParams); method public abstract android.content.Context createContextForSplit(String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.Context createDeviceProtectedStorageContext(); - method public abstract android.content.Context createDisplayContext(@NonNull android.view.Display); + method @DisplayContext public abstract android.content.Context createDisplayContext(@NonNull android.view.Display); method public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException; - method @NonNull public android.content.Context createWindowContext(int, @Nullable android.os.Bundle); - method @NonNull public android.content.Context createWindowContext(@NonNull android.view.Display, int, @Nullable android.os.Bundle); + method @NonNull @UiContext public android.content.Context createWindowContext(int, @Nullable android.os.Bundle); + method @NonNull @UiContext public android.content.Context createWindowContext(@NonNull android.view.Display, int, @Nullable android.os.Bundle); method public abstract String[] databaseList(); method public abstract boolean deleteDatabase(String); method public abstract boolean deleteFile(String); @@ -10514,7 +10514,7 @@ package android.content { field public static final String JOB_SCHEDULER_SERVICE = "jobscheduler"; field public static final String KEYGUARD_SERVICE = "keyguard"; field public static final String LAUNCHER_APPS_SERVICE = "launcherapps"; - field public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater"; + field @UiContext public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater"; field public static final String LOCATION_SERVICE = "location"; field public static final String MEDIA_COMMUNICATION_SERVICE = "media_communication"; field public static final String MEDIA_METRICS_SERVICE = "media_metrics"; @@ -10559,12 +10559,12 @@ package android.content { field public static final String VIBRATOR_MANAGER_SERVICE = "vibrator_manager"; field public static final String VIBRATOR_SERVICE = "vibrator"; field public static final String VPN_MANAGEMENT_SERVICE = "vpn_management"; - field public static final String WALLPAPER_SERVICE = "wallpaper"; + field @UiContext public static final String WALLPAPER_SERVICE = "wallpaper"; field public static final String WIFI_AWARE_SERVICE = "wifiaware"; field public static final String WIFI_P2P_SERVICE = "wifip2p"; field public static final String WIFI_RTT_RANGING_SERVICE = "wifirtt"; field public static final String WIFI_SERVICE = "wifi"; - field public static final String WINDOW_SERVICE = "window"; + field @UiContext public static final String WINDOW_SERVICE = "window"; } public final class ContextParams { @@ -16687,13 +16687,9 @@ package android.graphics.drawable { public class RippleDrawable extends android.graphics.drawable.LayerDrawable { ctor public RippleDrawable(@NonNull android.content.res.ColorStateList, @Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable); method public int getRadius(); - method public int getRippleStyle(); method public void setColor(android.content.res.ColorStateList); method public void setRadius(int); - method public void setRippleStyle(int) throws java.lang.IllegalArgumentException; field public static final int RADIUS_AUTO = -1; // 0xffffffff - field public static final int STYLE_PATTERNED = 1; // 0x1 - field public static final int STYLE_SOLID = 0; // 0x0 } public class RotateDrawable extends android.graphics.drawable.DrawableWrapper { @@ -19058,7 +19054,7 @@ package android.inputmethodservice { method public void startInternalChanges(); } - public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService { + @UiContext public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService { ctor public InputMethodService(); method @Deprecated public boolean enableHardwareAcceleration(); method public int getBackDisposition(); @@ -20569,6 +20565,7 @@ package android.media { method @NonNull public android.media.AudioRecord.Builder setAudioPlaybackCaptureConfig(@NonNull android.media.AudioPlaybackCaptureConfiguration); method public android.media.AudioRecord.Builder setAudioSource(int) throws java.lang.IllegalArgumentException; method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException; + method @NonNull public android.media.AudioRecord.Builder setContext(@NonNull android.content.Context); method @NonNull public android.media.AudioRecord.Builder setPrivacySensitive(boolean); } @@ -22743,7 +22740,8 @@ package android.media { } public class MediaRecorder implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection { - ctor public MediaRecorder(); + ctor @Deprecated public MediaRecorder(); + ctor public MediaRecorder(@NonNull android.content.Context); method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method protected void finalize(); method public java.util.List<android.media.MicrophoneInfo> getActiveMicrophones() throws java.io.IOException; @@ -26140,10 +26138,6 @@ package android.net { ctor public NetworkSpecifier(); } - public class ParseException extends java.lang.RuntimeException { - field public String response; - } - public abstract class PlatformVpnProfile { method public final int getType(); method @NonNull public final String getTypeString(); @@ -26555,236 +26549,236 @@ package android.net.nsd { package android.net.rtp { - public class AudioCodec { - method public static android.net.rtp.AudioCodec getCodec(int, String, String); - method public static android.net.rtp.AudioCodec[] getCodecs(); - field public static final android.net.rtp.AudioCodec AMR; - field public static final android.net.rtp.AudioCodec GSM; - field public static final android.net.rtp.AudioCodec GSM_EFR; - field public static final android.net.rtp.AudioCodec PCMA; - field public static final android.net.rtp.AudioCodec PCMU; - field public final String fmtp; - field public final String rtpmap; - field public final int type; + @Deprecated public class AudioCodec { + method @Deprecated public static android.net.rtp.AudioCodec getCodec(int, String, String); + method @Deprecated public static android.net.rtp.AudioCodec[] getCodecs(); + field @Deprecated public static final android.net.rtp.AudioCodec AMR; + field @Deprecated public static final android.net.rtp.AudioCodec GSM; + field @Deprecated public static final android.net.rtp.AudioCodec GSM_EFR; + field @Deprecated public static final android.net.rtp.AudioCodec PCMA; + field @Deprecated public static final android.net.rtp.AudioCodec PCMU; + field @Deprecated public final String fmtp; + field @Deprecated public final String rtpmap; + field @Deprecated public final int type; } - public class AudioGroup { + @Deprecated public class AudioGroup { ctor @Deprecated public AudioGroup(); - ctor public AudioGroup(@NonNull android.content.Context); - method public void clear(); - method public int getMode(); - method public android.net.rtp.AudioStream[] getStreams(); - method public void sendDtmf(int); - method public void setMode(int); - field public static final int MODE_ECHO_SUPPRESSION = 3; // 0x3 - field public static final int MODE_MUTED = 1; // 0x1 - field public static final int MODE_NORMAL = 2; // 0x2 - field public static final int MODE_ON_HOLD = 0; // 0x0 - } - - public class AudioStream extends android.net.rtp.RtpStream { - ctor public AudioStream(java.net.InetAddress) throws java.net.SocketException; - method public android.net.rtp.AudioCodec getCodec(); - method public int getDtmfType(); - method public android.net.rtp.AudioGroup getGroup(); - method public final boolean isBusy(); - method public void join(android.net.rtp.AudioGroup); - method public void setCodec(android.net.rtp.AudioCodec); - method public void setDtmfType(int); - } - - public class RtpStream { - method public void associate(java.net.InetAddress, int); - method public java.net.InetAddress getLocalAddress(); - method public int getLocalPort(); - method public int getMode(); - method public java.net.InetAddress getRemoteAddress(); - method public int getRemotePort(); - method public boolean isBusy(); - method public void release(); - method public void setMode(int); - field public static final int MODE_NORMAL = 0; // 0x0 - field public static final int MODE_RECEIVE_ONLY = 2; // 0x2 - field public static final int MODE_SEND_ONLY = 1; // 0x1 + ctor @Deprecated public AudioGroup(@NonNull android.content.Context); + method @Deprecated public void clear(); + method @Deprecated public int getMode(); + method @Deprecated public android.net.rtp.AudioStream[] getStreams(); + method @Deprecated public void sendDtmf(int); + method @Deprecated public void setMode(int); + field @Deprecated public static final int MODE_ECHO_SUPPRESSION = 3; // 0x3 + field @Deprecated public static final int MODE_MUTED = 1; // 0x1 + field @Deprecated public static final int MODE_NORMAL = 2; // 0x2 + field @Deprecated public static final int MODE_ON_HOLD = 0; // 0x0 + } + + @Deprecated public class AudioStream extends android.net.rtp.RtpStream { + ctor @Deprecated public AudioStream(java.net.InetAddress) throws java.net.SocketException; + method @Deprecated public android.net.rtp.AudioCodec getCodec(); + method @Deprecated public int getDtmfType(); + method @Deprecated public android.net.rtp.AudioGroup getGroup(); + method @Deprecated public final boolean isBusy(); + method @Deprecated public void join(android.net.rtp.AudioGroup); + method @Deprecated public void setCodec(android.net.rtp.AudioCodec); + method @Deprecated public void setDtmfType(int); + } + + @Deprecated public class RtpStream { + method @Deprecated public void associate(java.net.InetAddress, int); + method @Deprecated public java.net.InetAddress getLocalAddress(); + method @Deprecated public int getLocalPort(); + method @Deprecated public int getMode(); + method @Deprecated public java.net.InetAddress getRemoteAddress(); + method @Deprecated public int getRemotePort(); + method @Deprecated public boolean isBusy(); + method @Deprecated public void release(); + method @Deprecated public void setMode(int); + field @Deprecated public static final int MODE_NORMAL = 0; // 0x0 + field @Deprecated public static final int MODE_RECEIVE_ONLY = 2; // 0x2 + field @Deprecated public static final int MODE_SEND_ONLY = 1; // 0x1 } } package android.net.sip { - public class SipAudioCall { - ctor public SipAudioCall(android.content.Context, android.net.sip.SipProfile); - method public void answerCall(int) throws android.net.sip.SipException; - method public void attachCall(android.net.sip.SipSession, String) throws android.net.sip.SipException; - method public void close(); - method public void continueCall(int) throws android.net.sip.SipException; - method public void endCall() throws android.net.sip.SipException; - method public android.net.sip.SipProfile getLocalProfile(); - method public android.net.sip.SipProfile getPeerProfile(); - method public int getState(); - method public void holdCall(int) throws android.net.sip.SipException; - method public boolean isInCall(); - method public boolean isMuted(); - method public boolean isOnHold(); - method public void makeCall(android.net.sip.SipProfile, android.net.sip.SipSession, int) throws android.net.sip.SipException; - method public void sendDtmf(int); - method public void sendDtmf(int, android.os.Message); - method public void setListener(android.net.sip.SipAudioCall.Listener); - method public void setListener(android.net.sip.SipAudioCall.Listener, boolean); - method public void setSpeakerMode(boolean); - method public void startAudio(); - method public void toggleMute(); - } - - public static class SipAudioCall.Listener { - ctor public SipAudioCall.Listener(); - method public void onCallBusy(android.net.sip.SipAudioCall); - method public void onCallEnded(android.net.sip.SipAudioCall); - method public void onCallEstablished(android.net.sip.SipAudioCall); - method public void onCallHeld(android.net.sip.SipAudioCall); - method public void onCalling(android.net.sip.SipAudioCall); - method public void onChanged(android.net.sip.SipAudioCall); - method public void onError(android.net.sip.SipAudioCall, int, String); - method public void onReadyToCall(android.net.sip.SipAudioCall); - method public void onRinging(android.net.sip.SipAudioCall, android.net.sip.SipProfile); - method public void onRingingBack(android.net.sip.SipAudioCall); - } - - public class SipErrorCode { - method public static String toString(int); - field public static final int CLIENT_ERROR = -4; // 0xfffffffc - field public static final int CROSS_DOMAIN_AUTHENTICATION = -11; // 0xfffffff5 - field public static final int DATA_CONNECTION_LOST = -10; // 0xfffffff6 - field public static final int INVALID_CREDENTIALS = -8; // 0xfffffff8 - field public static final int INVALID_REMOTE_URI = -6; // 0xfffffffa - field public static final int IN_PROGRESS = -9; // 0xfffffff7 - field public static final int NO_ERROR = 0; // 0x0 - field public static final int PEER_NOT_REACHABLE = -7; // 0xfffffff9 - field public static final int SERVER_ERROR = -2; // 0xfffffffe - field public static final int SERVER_UNREACHABLE = -12; // 0xfffffff4 - field public static final int SOCKET_ERROR = -1; // 0xffffffff - field public static final int TIME_OUT = -5; // 0xfffffffb - field public static final int TRANSACTION_TERMINTED = -3; // 0xfffffffd - } - - public class SipException extends java.lang.Exception { - ctor public SipException(); - ctor public SipException(String); - ctor public SipException(String, Throwable); - } - - public class SipManager { - method public void close(String) throws android.net.sip.SipException; - method public android.net.sip.SipSession createSipSession(android.net.sip.SipProfile, android.net.sip.SipSession.Listener) throws android.net.sip.SipException; - method public static String getCallId(android.content.Intent); - method public static String getOfferSessionDescription(android.content.Intent); - method public android.net.sip.SipSession getSessionFor(android.content.Intent) throws android.net.sip.SipException; - method public static boolean isApiSupported(android.content.Context); - method public static boolean isIncomingCallIntent(android.content.Intent); - method public boolean isOpened(String) throws android.net.sip.SipException; - method public boolean isRegistered(String) throws android.net.sip.SipException; - method public static boolean isSipWifiOnly(android.content.Context); - method public static boolean isVoipSupported(android.content.Context); - method public android.net.sip.SipAudioCall makeAudioCall(android.net.sip.SipProfile, android.net.sip.SipProfile, android.net.sip.SipAudioCall.Listener, int) throws android.net.sip.SipException; - method public android.net.sip.SipAudioCall makeAudioCall(String, String, android.net.sip.SipAudioCall.Listener, int) throws android.net.sip.SipException; - method public static android.net.sip.SipManager newInstance(android.content.Context); - method public void open(android.net.sip.SipProfile) throws android.net.sip.SipException; - method public void open(android.net.sip.SipProfile, android.app.PendingIntent, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; - method public void register(android.net.sip.SipProfile, int, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; - method public void setRegistrationListener(String, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; - method public android.net.sip.SipAudioCall takeAudioCall(android.content.Intent, android.net.sip.SipAudioCall.Listener) throws android.net.sip.SipException; - method public void unregister(android.net.sip.SipProfile, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; - field public static final String EXTRA_CALL_ID = "android:sipCallID"; - field public static final String EXTRA_OFFER_SD = "android:sipOfferSD"; - field public static final int INCOMING_CALL_RESULT_CODE = 101; // 0x65 - } - - public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable { - method public int describeContents(); - method public String getAuthUserName(); - method public boolean getAutoRegistration(); - method public String getDisplayName(); - method public String getPassword(); - method public int getPort(); - method public String getProfileName(); - method public String getProtocol(); - method public String getProxyAddress(); - method public boolean getSendKeepAlive(); - method public String getSipDomain(); - method public String getUriString(); - method public String getUserName(); - method public void setCallingUid(int); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.net.sip.SipProfile> CREATOR; - } - - public static class SipProfile.Builder { - ctor public SipProfile.Builder(android.net.sip.SipProfile); - ctor public SipProfile.Builder(String) throws java.text.ParseException; - ctor public SipProfile.Builder(String, String) throws java.text.ParseException; - method public android.net.sip.SipProfile build(); - method public android.net.sip.SipProfile.Builder setAuthUserName(String); - method public android.net.sip.SipProfile.Builder setAutoRegistration(boolean); - method public android.net.sip.SipProfile.Builder setDisplayName(String); - method public android.net.sip.SipProfile.Builder setOutboundProxy(String); - method public android.net.sip.SipProfile.Builder setPassword(String); - method public android.net.sip.SipProfile.Builder setPort(int) throws java.lang.IllegalArgumentException; - method public android.net.sip.SipProfile.Builder setProfileName(String); - method public android.net.sip.SipProfile.Builder setProtocol(String) throws java.lang.IllegalArgumentException; - method public android.net.sip.SipProfile.Builder setSendKeepAlive(boolean); - } - - public interface SipRegistrationListener { - method public void onRegistering(String); - method public void onRegistrationDone(String, long); - method public void onRegistrationFailed(String, int, String); - } - - public final class SipSession { - method public void answerCall(String, int); - method public void changeCall(String, int); - method public void endCall(); - method public String getCallId(); - method public String getLocalIp(); - method public android.net.sip.SipProfile getLocalProfile(); - method public android.net.sip.SipProfile getPeerProfile(); - method public int getState(); - method public boolean isInCall(); - method public void makeCall(android.net.sip.SipProfile, String, int); - method public void register(int); - method public void setListener(android.net.sip.SipSession.Listener); - method public void unregister(); - } - - public static class SipSession.Listener { - ctor public SipSession.Listener(); - method public void onCallBusy(android.net.sip.SipSession); - method public void onCallChangeFailed(android.net.sip.SipSession, int, String); - method public void onCallEnded(android.net.sip.SipSession); - method public void onCallEstablished(android.net.sip.SipSession, String); - method public void onCalling(android.net.sip.SipSession); - method public void onError(android.net.sip.SipSession, int, String); - method public void onRegistering(android.net.sip.SipSession); - method public void onRegistrationDone(android.net.sip.SipSession, int); - method public void onRegistrationFailed(android.net.sip.SipSession, int, String); - method public void onRegistrationTimeout(android.net.sip.SipSession); - method public void onRinging(android.net.sip.SipSession, android.net.sip.SipProfile, String); - method public void onRingingBack(android.net.sip.SipSession); - } - - public static class SipSession.State { - method public static String toString(int); - field public static final int DEREGISTERING = 2; // 0x2 - field public static final int INCOMING_CALL = 3; // 0x3 - field public static final int INCOMING_CALL_ANSWERING = 4; // 0x4 - field public static final int IN_CALL = 8; // 0x8 - field public static final int NOT_DEFINED = 101; // 0x65 - field public static final int OUTGOING_CALL = 5; // 0x5 - field public static final int OUTGOING_CALL_CANCELING = 7; // 0x7 - field public static final int OUTGOING_CALL_RING_BACK = 6; // 0x6 - field public static final int PINGING = 9; // 0x9 - field public static final int READY_TO_CALL = 0; // 0x0 - field public static final int REGISTERING = 1; // 0x1 + @Deprecated public class SipAudioCall { + ctor @Deprecated public SipAudioCall(android.content.Context, android.net.sip.SipProfile); + method @Deprecated public void answerCall(int) throws android.net.sip.SipException; + method @Deprecated public void attachCall(android.net.sip.SipSession, String) throws android.net.sip.SipException; + method @Deprecated public void close(); + method @Deprecated public void continueCall(int) throws android.net.sip.SipException; + method @Deprecated public void endCall() throws android.net.sip.SipException; + method @Deprecated public android.net.sip.SipProfile getLocalProfile(); + method @Deprecated public android.net.sip.SipProfile getPeerProfile(); + method @Deprecated public int getState(); + method @Deprecated public void holdCall(int) throws android.net.sip.SipException; + method @Deprecated public boolean isInCall(); + method @Deprecated public boolean isMuted(); + method @Deprecated public boolean isOnHold(); + method @Deprecated public void makeCall(android.net.sip.SipProfile, android.net.sip.SipSession, int) throws android.net.sip.SipException; + method @Deprecated public void sendDtmf(int); + method @Deprecated public void sendDtmf(int, android.os.Message); + method @Deprecated public void setListener(android.net.sip.SipAudioCall.Listener); + method @Deprecated public void setListener(android.net.sip.SipAudioCall.Listener, boolean); + method @Deprecated public void setSpeakerMode(boolean); + method @Deprecated public void startAudio(); + method @Deprecated public void toggleMute(); + } + + @Deprecated public static class SipAudioCall.Listener { + ctor @Deprecated public SipAudioCall.Listener(); + method @Deprecated public void onCallBusy(android.net.sip.SipAudioCall); + method @Deprecated public void onCallEnded(android.net.sip.SipAudioCall); + method @Deprecated public void onCallEstablished(android.net.sip.SipAudioCall); + method @Deprecated public void onCallHeld(android.net.sip.SipAudioCall); + method @Deprecated public void onCalling(android.net.sip.SipAudioCall); + method @Deprecated public void onChanged(android.net.sip.SipAudioCall); + method @Deprecated public void onError(android.net.sip.SipAudioCall, int, String); + method @Deprecated public void onReadyToCall(android.net.sip.SipAudioCall); + method @Deprecated public void onRinging(android.net.sip.SipAudioCall, android.net.sip.SipProfile); + method @Deprecated public void onRingingBack(android.net.sip.SipAudioCall); + } + + @Deprecated public class SipErrorCode { + method @Deprecated public static String toString(int); + field @Deprecated public static final int CLIENT_ERROR = -4; // 0xfffffffc + field @Deprecated public static final int CROSS_DOMAIN_AUTHENTICATION = -11; // 0xfffffff5 + field @Deprecated public static final int DATA_CONNECTION_LOST = -10; // 0xfffffff6 + field @Deprecated public static final int INVALID_CREDENTIALS = -8; // 0xfffffff8 + field @Deprecated public static final int INVALID_REMOTE_URI = -6; // 0xfffffffa + field @Deprecated public static final int IN_PROGRESS = -9; // 0xfffffff7 + field @Deprecated public static final int NO_ERROR = 0; // 0x0 + field @Deprecated public static final int PEER_NOT_REACHABLE = -7; // 0xfffffff9 + field @Deprecated public static final int SERVER_ERROR = -2; // 0xfffffffe + field @Deprecated public static final int SERVER_UNREACHABLE = -12; // 0xfffffff4 + field @Deprecated public static final int SOCKET_ERROR = -1; // 0xffffffff + field @Deprecated public static final int TIME_OUT = -5; // 0xfffffffb + field @Deprecated public static final int TRANSACTION_TERMINTED = -3; // 0xfffffffd + } + + @Deprecated public class SipException extends java.lang.Exception { + ctor @Deprecated public SipException(); + ctor @Deprecated public SipException(String); + ctor @Deprecated public SipException(String, Throwable); + } + + @Deprecated public class SipManager { + method @Deprecated public void close(String) throws android.net.sip.SipException; + method @Deprecated public android.net.sip.SipSession createSipSession(android.net.sip.SipProfile, android.net.sip.SipSession.Listener) throws android.net.sip.SipException; + method @Deprecated public static String getCallId(android.content.Intent); + method @Deprecated public static String getOfferSessionDescription(android.content.Intent); + method @Deprecated public android.net.sip.SipSession getSessionFor(android.content.Intent) throws android.net.sip.SipException; + method @Deprecated public static boolean isApiSupported(android.content.Context); + method @Deprecated public static boolean isIncomingCallIntent(android.content.Intent); + method @Deprecated public boolean isOpened(String) throws android.net.sip.SipException; + method @Deprecated public boolean isRegistered(String) throws android.net.sip.SipException; + method @Deprecated public static boolean isSipWifiOnly(android.content.Context); + method @Deprecated public static boolean isVoipSupported(android.content.Context); + method @Deprecated public android.net.sip.SipAudioCall makeAudioCall(android.net.sip.SipProfile, android.net.sip.SipProfile, android.net.sip.SipAudioCall.Listener, int) throws android.net.sip.SipException; + method @Deprecated public android.net.sip.SipAudioCall makeAudioCall(String, String, android.net.sip.SipAudioCall.Listener, int) throws android.net.sip.SipException; + method @Deprecated public static android.net.sip.SipManager newInstance(android.content.Context); + method @Deprecated public void open(android.net.sip.SipProfile) throws android.net.sip.SipException; + method @Deprecated public void open(android.net.sip.SipProfile, android.app.PendingIntent, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; + method @Deprecated public void register(android.net.sip.SipProfile, int, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; + method @Deprecated public void setRegistrationListener(String, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; + method @Deprecated public android.net.sip.SipAudioCall takeAudioCall(android.content.Intent, android.net.sip.SipAudioCall.Listener) throws android.net.sip.SipException; + method @Deprecated public void unregister(android.net.sip.SipProfile, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; + field @Deprecated public static final String EXTRA_CALL_ID = "android:sipCallID"; + field @Deprecated public static final String EXTRA_OFFER_SD = "android:sipOfferSD"; + field @Deprecated public static final int INCOMING_CALL_RESULT_CODE = 101; // 0x65 + } + + @Deprecated public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable { + method @Deprecated public int describeContents(); + method @Deprecated public String getAuthUserName(); + method @Deprecated public boolean getAutoRegistration(); + method @Deprecated public String getDisplayName(); + method @Deprecated public String getPassword(); + method @Deprecated public int getPort(); + method @Deprecated public String getProfileName(); + method @Deprecated public String getProtocol(); + method @Deprecated public String getProxyAddress(); + method @Deprecated public boolean getSendKeepAlive(); + method @Deprecated public String getSipDomain(); + method @Deprecated public String getUriString(); + method @Deprecated public String getUserName(); + method @Deprecated public void setCallingUid(int); + method @Deprecated public void writeToParcel(android.os.Parcel, int); + field @Deprecated public static final android.os.Parcelable.Creator<android.net.sip.SipProfile> CREATOR; + } + + @Deprecated public static class SipProfile.Builder { + ctor @Deprecated public SipProfile.Builder(android.net.sip.SipProfile); + ctor @Deprecated public SipProfile.Builder(String) throws java.text.ParseException; + ctor @Deprecated public SipProfile.Builder(String, String) throws java.text.ParseException; + method @Deprecated public android.net.sip.SipProfile build(); + method @Deprecated public android.net.sip.SipProfile.Builder setAuthUserName(String); + method @Deprecated public android.net.sip.SipProfile.Builder setAutoRegistration(boolean); + method @Deprecated public android.net.sip.SipProfile.Builder setDisplayName(String); + method @Deprecated public android.net.sip.SipProfile.Builder setOutboundProxy(String); + method @Deprecated public android.net.sip.SipProfile.Builder setPassword(String); + method @Deprecated public android.net.sip.SipProfile.Builder setPort(int) throws java.lang.IllegalArgumentException; + method @Deprecated public android.net.sip.SipProfile.Builder setProfileName(String); + method @Deprecated public android.net.sip.SipProfile.Builder setProtocol(String) throws java.lang.IllegalArgumentException; + method @Deprecated public android.net.sip.SipProfile.Builder setSendKeepAlive(boolean); + } + + @Deprecated public interface SipRegistrationListener { + method @Deprecated public void onRegistering(String); + method @Deprecated public void onRegistrationDone(String, long); + method @Deprecated public void onRegistrationFailed(String, int, String); + } + + @Deprecated public final class SipSession { + method @Deprecated public void answerCall(String, int); + method @Deprecated public void changeCall(String, int); + method @Deprecated public void endCall(); + method @Deprecated public String getCallId(); + method @Deprecated public String getLocalIp(); + method @Deprecated public android.net.sip.SipProfile getLocalProfile(); + method @Deprecated public android.net.sip.SipProfile getPeerProfile(); + method @Deprecated public int getState(); + method @Deprecated public boolean isInCall(); + method @Deprecated public void makeCall(android.net.sip.SipProfile, String, int); + method @Deprecated public void register(int); + method @Deprecated public void setListener(android.net.sip.SipSession.Listener); + method @Deprecated public void unregister(); + } + + @Deprecated public static class SipSession.Listener { + ctor @Deprecated public SipSession.Listener(); + method @Deprecated public void onCallBusy(android.net.sip.SipSession); + method @Deprecated public void onCallChangeFailed(android.net.sip.SipSession, int, String); + method @Deprecated public void onCallEnded(android.net.sip.SipSession); + method @Deprecated public void onCallEstablished(android.net.sip.SipSession, String); + method @Deprecated public void onCalling(android.net.sip.SipSession); + method @Deprecated public void onError(android.net.sip.SipSession, int, String); + method @Deprecated public void onRegistering(android.net.sip.SipSession); + method @Deprecated public void onRegistrationDone(android.net.sip.SipSession, int); + method @Deprecated public void onRegistrationFailed(android.net.sip.SipSession, int, String); + method @Deprecated public void onRegistrationTimeout(android.net.sip.SipSession); + method @Deprecated public void onRinging(android.net.sip.SipSession, android.net.sip.SipProfile, String); + method @Deprecated public void onRingingBack(android.net.sip.SipSession); + } + + @Deprecated public static class SipSession.State { + method @Deprecated public static String toString(int); + field @Deprecated public static final int DEREGISTERING = 2; // 0x2 + field @Deprecated public static final int INCOMING_CALL = 3; // 0x3 + field @Deprecated public static final int INCOMING_CALL_ANSWERING = 4; // 0x4 + field @Deprecated public static final int IN_CALL = 8; // 0x8 + field @Deprecated public static final int NOT_DEFINED = 101; // 0x65 + field @Deprecated public static final int OUTGOING_CALL = 5; // 0x5 + field @Deprecated public static final int OUTGOING_CALL_CANCELING = 7; // 0x7 + field @Deprecated public static final int OUTGOING_CALL_RING_BACK = 6; // 0x6 + field @Deprecated public static final int PINGING = 9; // 0x9 + field @Deprecated public static final int READY_TO_CALL = 0; // 0x0 + field @Deprecated public static final int REGISTERING = 1; // 0x1 } } @@ -30430,6 +30424,7 @@ package android.os { field public static final String BASE_OS; field public static final String CODENAME; field public static final String INCREMENTAL; + field public static final int MEDIA_PERFORMANCE_CLASS; field public static final int PREVIEW_SDK_INT; field public static final String RELEASE; field @NonNull public static final String RELEASE_OR_CODENAME; @@ -35651,721 +35646,721 @@ package android.provider { package android.renderscript { - public class Allocation extends android.renderscript.BaseObj { - method public void copy1DRangeFrom(int, int, Object); - method public void copy1DRangeFrom(int, int, int[]); - method public void copy1DRangeFrom(int, int, short[]); - method public void copy1DRangeFrom(int, int, byte[]); - method public void copy1DRangeFrom(int, int, float[]); - method public void copy1DRangeFrom(int, int, android.renderscript.Allocation, int); - method public void copy1DRangeFromUnchecked(int, int, Object); - method public void copy1DRangeFromUnchecked(int, int, int[]); - method public void copy1DRangeFromUnchecked(int, int, short[]); - method public void copy1DRangeFromUnchecked(int, int, byte[]); - method public void copy1DRangeFromUnchecked(int, int, float[]); - method public void copy1DRangeTo(int, int, Object); - method public void copy1DRangeTo(int, int, int[]); - method public void copy1DRangeTo(int, int, short[]); - method public void copy1DRangeTo(int, int, byte[]); - method public void copy1DRangeTo(int, int, float[]); - method public void copy1DRangeToUnchecked(int, int, Object); - method public void copy1DRangeToUnchecked(int, int, int[]); - method public void copy1DRangeToUnchecked(int, int, short[]); - method public void copy1DRangeToUnchecked(int, int, byte[]); - method public void copy1DRangeToUnchecked(int, int, float[]); - method public void copy2DRangeFrom(int, int, int, int, Object); - method public void copy2DRangeFrom(int, int, int, int, byte[]); - method public void copy2DRangeFrom(int, int, int, int, short[]); - method public void copy2DRangeFrom(int, int, int, int, int[]); - method public void copy2DRangeFrom(int, int, int, int, float[]); - method public void copy2DRangeFrom(int, int, int, int, android.renderscript.Allocation, int, int); - method public void copy2DRangeFrom(int, int, android.graphics.Bitmap); - method public void copy2DRangeTo(int, int, int, int, Object); - method public void copy2DRangeTo(int, int, int, int, byte[]); - method public void copy2DRangeTo(int, int, int, int, short[]); - method public void copy2DRangeTo(int, int, int, int, int[]); - method public void copy2DRangeTo(int, int, int, int, float[]); - method public void copy3DRangeFrom(int, int, int, int, int, int, Object); - method public void copy3DRangeFrom(int, int, int, int, int, int, android.renderscript.Allocation, int, int, int); - method public void copy3DRangeTo(int, int, int, int, int, int, Object); - method public void copyFrom(android.renderscript.BaseObj[]); - method public void copyFrom(Object); - method public void copyFrom(int[]); - method public void copyFrom(short[]); - method public void copyFrom(byte[]); - method public void copyFrom(float[]); - method public void copyFrom(android.graphics.Bitmap); - method public void copyFrom(android.renderscript.Allocation); - method public void copyFromUnchecked(Object); - method public void copyFromUnchecked(int[]); - method public void copyFromUnchecked(short[]); - method public void copyFromUnchecked(byte[]); - method public void copyFromUnchecked(float[]); - method public void copyTo(android.graphics.Bitmap); - method public void copyTo(Object); - method public void copyTo(byte[]); - method public void copyTo(short[]); - method public void copyTo(int[]); - method public void copyTo(float[]); - method public static android.renderscript.Allocation[] createAllocations(android.renderscript.RenderScript, android.renderscript.Type, int, int); - method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int); - method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap); - method public static android.renderscript.Allocation createCubemapFromCubeFaces(android.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int); - method public static android.renderscript.Allocation createCubemapFromCubeFaces(android.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap); - method public static android.renderscript.Allocation createFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int); - method public static android.renderscript.Allocation createFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap); - method public static android.renderscript.Allocation createFromBitmapResource(android.renderscript.RenderScript, android.content.res.Resources, int, android.renderscript.Allocation.MipmapControl, int); - method public static android.renderscript.Allocation createFromBitmapResource(android.renderscript.RenderScript, android.content.res.Resources, int); - method public static android.renderscript.Allocation createFromString(android.renderscript.RenderScript, String, int); - method public static android.renderscript.Allocation createSized(android.renderscript.RenderScript, android.renderscript.Element, int, int); - method public static android.renderscript.Allocation createSized(android.renderscript.RenderScript, android.renderscript.Element, int); - method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type, android.renderscript.Allocation.MipmapControl, int); - method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type, int); - method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type); - method public void generateMipmaps(); - method public java.nio.ByteBuffer getByteBuffer(); - method public int getBytesSize(); - method public android.renderscript.Element getElement(); - method public long getStride(); - method public android.view.Surface getSurface(); - method public long getTimeStamp(); - method public android.renderscript.Type getType(); - method public int getUsage(); - method public void ioReceive(); - method public void ioSend(); + @Deprecated public class Allocation extends android.renderscript.BaseObj { + method @Deprecated public void copy1DRangeFrom(int, int, Object); + method @Deprecated public void copy1DRangeFrom(int, int, int[]); + method @Deprecated public void copy1DRangeFrom(int, int, short[]); + method @Deprecated public void copy1DRangeFrom(int, int, byte[]); + method @Deprecated public void copy1DRangeFrom(int, int, float[]); + method @Deprecated public void copy1DRangeFrom(int, int, android.renderscript.Allocation, int); + method @Deprecated public void copy1DRangeFromUnchecked(int, int, Object); + method @Deprecated public void copy1DRangeFromUnchecked(int, int, int[]); + method @Deprecated public void copy1DRangeFromUnchecked(int, int, short[]); + method @Deprecated public void copy1DRangeFromUnchecked(int, int, byte[]); + method @Deprecated public void copy1DRangeFromUnchecked(int, int, float[]); + method @Deprecated public void copy1DRangeTo(int, int, Object); + method @Deprecated public void copy1DRangeTo(int, int, int[]); + method @Deprecated public void copy1DRangeTo(int, int, short[]); + method @Deprecated public void copy1DRangeTo(int, int, byte[]); + method @Deprecated public void copy1DRangeTo(int, int, float[]); + method @Deprecated public void copy1DRangeToUnchecked(int, int, Object); + method @Deprecated public void copy1DRangeToUnchecked(int, int, int[]); + method @Deprecated public void copy1DRangeToUnchecked(int, int, short[]); + method @Deprecated public void copy1DRangeToUnchecked(int, int, byte[]); + method @Deprecated public void copy1DRangeToUnchecked(int, int, float[]); + method @Deprecated public void copy2DRangeFrom(int, int, int, int, Object); + method @Deprecated public void copy2DRangeFrom(int, int, int, int, byte[]); + method @Deprecated public void copy2DRangeFrom(int, int, int, int, short[]); + method @Deprecated public void copy2DRangeFrom(int, int, int, int, int[]); + method @Deprecated public void copy2DRangeFrom(int, int, int, int, float[]); + method @Deprecated public void copy2DRangeFrom(int, int, int, int, android.renderscript.Allocation, int, int); + method @Deprecated public void copy2DRangeFrom(int, int, android.graphics.Bitmap); + method @Deprecated public void copy2DRangeTo(int, int, int, int, Object); + method @Deprecated public void copy2DRangeTo(int, int, int, int, byte[]); + method @Deprecated public void copy2DRangeTo(int, int, int, int, short[]); + method @Deprecated public void copy2DRangeTo(int, int, int, int, int[]); + method @Deprecated public void copy2DRangeTo(int, int, int, int, float[]); + method @Deprecated public void copy3DRangeFrom(int, int, int, int, int, int, Object); + method @Deprecated public void copy3DRangeFrom(int, int, int, int, int, int, android.renderscript.Allocation, int, int, int); + method @Deprecated public void copy3DRangeTo(int, int, int, int, int, int, Object); + method @Deprecated public void copyFrom(android.renderscript.BaseObj[]); + method @Deprecated public void copyFrom(Object); + method @Deprecated public void copyFrom(int[]); + method @Deprecated public void copyFrom(short[]); + method @Deprecated public void copyFrom(byte[]); + method @Deprecated public void copyFrom(float[]); + method @Deprecated public void copyFrom(android.graphics.Bitmap); + method @Deprecated public void copyFrom(android.renderscript.Allocation); + method @Deprecated public void copyFromUnchecked(Object); + method @Deprecated public void copyFromUnchecked(int[]); + method @Deprecated public void copyFromUnchecked(short[]); + method @Deprecated public void copyFromUnchecked(byte[]); + method @Deprecated public void copyFromUnchecked(float[]); + method @Deprecated public void copyTo(android.graphics.Bitmap); + method @Deprecated public void copyTo(Object); + method @Deprecated public void copyTo(byte[]); + method @Deprecated public void copyTo(short[]); + method @Deprecated public void copyTo(int[]); + method @Deprecated public void copyTo(float[]); + method @Deprecated public static android.renderscript.Allocation[] createAllocations(android.renderscript.RenderScript, android.renderscript.Type, int, int); + method @Deprecated public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int); + method @Deprecated public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap); + method @Deprecated public static android.renderscript.Allocation createCubemapFromCubeFaces(android.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int); + method @Deprecated public static android.renderscript.Allocation createCubemapFromCubeFaces(android.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap); + method @Deprecated public static android.renderscript.Allocation createFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int); + method @Deprecated public static android.renderscript.Allocation createFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap); + method @Deprecated public static android.renderscript.Allocation createFromBitmapResource(android.renderscript.RenderScript, android.content.res.Resources, int, android.renderscript.Allocation.MipmapControl, int); + method @Deprecated public static android.renderscript.Allocation createFromBitmapResource(android.renderscript.RenderScript, android.content.res.Resources, int); + method @Deprecated public static android.renderscript.Allocation createFromString(android.renderscript.RenderScript, String, int); + method @Deprecated public static android.renderscript.Allocation createSized(android.renderscript.RenderScript, android.renderscript.Element, int, int); + method @Deprecated public static android.renderscript.Allocation createSized(android.renderscript.RenderScript, android.renderscript.Element, int); + method @Deprecated public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type, android.renderscript.Allocation.MipmapControl, int); + method @Deprecated public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type, int); + method @Deprecated public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type); + method @Deprecated public void generateMipmaps(); + method @Deprecated public java.nio.ByteBuffer getByteBuffer(); + method @Deprecated public int getBytesSize(); + method @Deprecated public android.renderscript.Element getElement(); + method @Deprecated public long getStride(); + method @Deprecated public android.view.Surface getSurface(); + method @Deprecated public long getTimeStamp(); + method @Deprecated public android.renderscript.Type getType(); + method @Deprecated public int getUsage(); + method @Deprecated public void ioReceive(); + method @Deprecated public void ioSend(); method @Deprecated public void resize(int); - method public void setAutoPadding(boolean); - method public void setFromFieldPacker(int, android.renderscript.FieldPacker); - method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker); - method public void setFromFieldPacker(int, int, int, int, android.renderscript.FieldPacker); - method public void setOnBufferAvailableListener(android.renderscript.Allocation.OnBufferAvailableListener); - method public void setSurface(android.view.Surface); - method public void syncAll(int); - field public static final int USAGE_GRAPHICS_CONSTANTS = 8; // 0x8 - field public static final int USAGE_GRAPHICS_RENDER_TARGET = 16; // 0x10 - field public static final int USAGE_GRAPHICS_TEXTURE = 2; // 0x2 - field public static final int USAGE_GRAPHICS_VERTEX = 4; // 0x4 - field public static final int USAGE_IO_INPUT = 32; // 0x20 - field public static final int USAGE_IO_OUTPUT = 64; // 0x40 - field public static final int USAGE_SCRIPT = 1; // 0x1 - field public static final int USAGE_SHARED = 128; // 0x80 - } - - public enum Allocation.MipmapControl { - enum_constant public static final android.renderscript.Allocation.MipmapControl MIPMAP_FULL; - enum_constant public static final android.renderscript.Allocation.MipmapControl MIPMAP_NONE; - enum_constant public static final android.renderscript.Allocation.MipmapControl MIPMAP_ON_SYNC_TO_TEXTURE; - } - - public static interface Allocation.OnBufferAvailableListener { - method public void onBufferAvailable(android.renderscript.Allocation); - } - - public class AllocationAdapter extends android.renderscript.Allocation { - method public static android.renderscript.AllocationAdapter create1D(android.renderscript.RenderScript, android.renderscript.Allocation); - method public static android.renderscript.AllocationAdapter create2D(android.renderscript.RenderScript, android.renderscript.Allocation); - method public static android.renderscript.AllocationAdapter createTyped(android.renderscript.RenderScript, android.renderscript.Allocation, android.renderscript.Type); - method public void resize(int); - method public void setFace(android.renderscript.Type.CubemapFace); - method public void setLOD(int); - method public void setX(int); - method public void setY(int); - method public void setZ(int); - } - - public class BaseObj { - method public void destroy(); - method public String getName(); - method public void setName(String); + method @Deprecated public void setAutoPadding(boolean); + method @Deprecated public void setFromFieldPacker(int, android.renderscript.FieldPacker); + method @Deprecated public void setFromFieldPacker(int, int, android.renderscript.FieldPacker); + method @Deprecated public void setFromFieldPacker(int, int, int, int, android.renderscript.FieldPacker); + method @Deprecated public void setOnBufferAvailableListener(android.renderscript.Allocation.OnBufferAvailableListener); + method @Deprecated public void setSurface(android.view.Surface); + method @Deprecated public void syncAll(int); + field @Deprecated public static final int USAGE_GRAPHICS_CONSTANTS = 8; // 0x8 + field @Deprecated public static final int USAGE_GRAPHICS_RENDER_TARGET = 16; // 0x10 + field @Deprecated public static final int USAGE_GRAPHICS_TEXTURE = 2; // 0x2 + field @Deprecated public static final int USAGE_GRAPHICS_VERTEX = 4; // 0x4 + field @Deprecated public static final int USAGE_IO_INPUT = 32; // 0x20 + field @Deprecated public static final int USAGE_IO_OUTPUT = 64; // 0x40 + field @Deprecated public static final int USAGE_SCRIPT = 1; // 0x1 + field @Deprecated public static final int USAGE_SHARED = 128; // 0x80 + } + + @Deprecated public enum Allocation.MipmapControl { + enum_constant @Deprecated public static final android.renderscript.Allocation.MipmapControl MIPMAP_FULL; + enum_constant @Deprecated public static final android.renderscript.Allocation.MipmapControl MIPMAP_NONE; + enum_constant @Deprecated public static final android.renderscript.Allocation.MipmapControl MIPMAP_ON_SYNC_TO_TEXTURE; + } + + @Deprecated public static interface Allocation.OnBufferAvailableListener { + method @Deprecated public void onBufferAvailable(android.renderscript.Allocation); + } + + @Deprecated public class AllocationAdapter extends android.renderscript.Allocation { + method @Deprecated public static android.renderscript.AllocationAdapter create1D(android.renderscript.RenderScript, android.renderscript.Allocation); + method @Deprecated public static android.renderscript.AllocationAdapter create2D(android.renderscript.RenderScript, android.renderscript.Allocation); + method @Deprecated public static android.renderscript.AllocationAdapter createTyped(android.renderscript.RenderScript, android.renderscript.Allocation, android.renderscript.Type); + method @Deprecated public void resize(int); + method @Deprecated public void setFace(android.renderscript.Type.CubemapFace); + method @Deprecated public void setLOD(int); + method @Deprecated public void setX(int); + method @Deprecated public void setY(int); + method @Deprecated public void setZ(int); } - public class Byte2 { - ctor public Byte2(); - ctor public Byte2(byte, byte); - field public byte x; - field public byte y; - } - - public class Byte3 { - ctor public Byte3(); - ctor public Byte3(byte, byte, byte); - field public byte x; - field public byte y; - field public byte z; - } - - public class Byte4 { - ctor public Byte4(); - ctor public Byte4(byte, byte, byte, byte); - field public byte w; - field public byte x; - field public byte y; - field public byte z; - } - - public class Double2 { - ctor public Double2(); - ctor public Double2(double, double); - field public double x; - field public double y; - } - - public class Double3 { - ctor public Double3(); - ctor public Double3(double, double, double); - field public double x; - field public double y; - field public double z; - } - - public class Double4 { - ctor public Double4(); - ctor public Double4(double, double, double, double); - field public double w; - field public double x; - field public double y; - field public double z; - } - - public class Element extends android.renderscript.BaseObj { - method public static android.renderscript.Element ALLOCATION(android.renderscript.RenderScript); - method public static android.renderscript.Element A_8(android.renderscript.RenderScript); - method public static android.renderscript.Element BOOLEAN(android.renderscript.RenderScript); - method public static android.renderscript.Element ELEMENT(android.renderscript.RenderScript); - method public static android.renderscript.Element F16(android.renderscript.RenderScript); - method public static android.renderscript.Element F16_2(android.renderscript.RenderScript); - method public static android.renderscript.Element F16_3(android.renderscript.RenderScript); - method public static android.renderscript.Element F16_4(android.renderscript.RenderScript); - method public static android.renderscript.Element F32(android.renderscript.RenderScript); - method public static android.renderscript.Element F32_2(android.renderscript.RenderScript); - method public static android.renderscript.Element F32_3(android.renderscript.RenderScript); - method public static android.renderscript.Element F32_4(android.renderscript.RenderScript); - method public static android.renderscript.Element F64(android.renderscript.RenderScript); - method public static android.renderscript.Element F64_2(android.renderscript.RenderScript); - method public static android.renderscript.Element F64_3(android.renderscript.RenderScript); - method public static android.renderscript.Element F64_4(android.renderscript.RenderScript); - method public static android.renderscript.Element FONT(android.renderscript.RenderScript); - method public static android.renderscript.Element I16(android.renderscript.RenderScript); - method public static android.renderscript.Element I16_2(android.renderscript.RenderScript); - method public static android.renderscript.Element I16_3(android.renderscript.RenderScript); - method public static android.renderscript.Element I16_4(android.renderscript.RenderScript); - method public static android.renderscript.Element I32(android.renderscript.RenderScript); - method public static android.renderscript.Element I32_2(android.renderscript.RenderScript); - method public static android.renderscript.Element I32_3(android.renderscript.RenderScript); - method public static android.renderscript.Element I32_4(android.renderscript.RenderScript); - method public static android.renderscript.Element I64(android.renderscript.RenderScript); - method public static android.renderscript.Element I64_2(android.renderscript.RenderScript); - method public static android.renderscript.Element I64_3(android.renderscript.RenderScript); - method public static android.renderscript.Element I64_4(android.renderscript.RenderScript); - method public static android.renderscript.Element I8(android.renderscript.RenderScript); - method public static android.renderscript.Element I8_2(android.renderscript.RenderScript); - method public static android.renderscript.Element I8_3(android.renderscript.RenderScript); - method public static android.renderscript.Element I8_4(android.renderscript.RenderScript); + @Deprecated public class BaseObj { + method @Deprecated public void destroy(); + method @Deprecated public String getName(); + method @Deprecated public void setName(String); + } + + @Deprecated public class Byte2 { + ctor @Deprecated public Byte2(); + ctor @Deprecated public Byte2(byte, byte); + field @Deprecated public byte x; + field @Deprecated public byte y; + } + + @Deprecated public class Byte3 { + ctor @Deprecated public Byte3(); + ctor @Deprecated public Byte3(byte, byte, byte); + field @Deprecated public byte x; + field @Deprecated public byte y; + field @Deprecated public byte z; + } + + @Deprecated public class Byte4 { + ctor @Deprecated public Byte4(); + ctor @Deprecated public Byte4(byte, byte, byte, byte); + field @Deprecated public byte w; + field @Deprecated public byte x; + field @Deprecated public byte y; + field @Deprecated public byte z; + } + + @Deprecated public class Double2 { + ctor @Deprecated public Double2(); + ctor @Deprecated public Double2(double, double); + field @Deprecated public double x; + field @Deprecated public double y; + } + + @Deprecated public class Double3 { + ctor @Deprecated public Double3(); + ctor @Deprecated public Double3(double, double, double); + field @Deprecated public double x; + field @Deprecated public double y; + field @Deprecated public double z; + } + + @Deprecated public class Double4 { + ctor @Deprecated public Double4(); + ctor @Deprecated public Double4(double, double, double, double); + field @Deprecated public double w; + field @Deprecated public double x; + field @Deprecated public double y; + field @Deprecated public double z; + } + + @Deprecated public class Element extends android.renderscript.BaseObj { + method @Deprecated public static android.renderscript.Element ALLOCATION(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element A_8(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element BOOLEAN(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element ELEMENT(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F16(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F16_2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F16_3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F16_4(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F32(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F32_2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F32_3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F32_4(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F64(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F64_2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F64_3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element F64_4(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element FONT(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I16(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I16_2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I16_3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I16_4(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I32(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I32_2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I32_3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I32_4(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I64(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I64_2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I64_3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I64_4(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I8(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I8_2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I8_3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element I8_4(android.renderscript.RenderScript); method @Deprecated public static android.renderscript.Element MATRIX4X4(android.renderscript.RenderScript); - method public static android.renderscript.Element MATRIX_2X2(android.renderscript.RenderScript); - method public static android.renderscript.Element MATRIX_3X3(android.renderscript.RenderScript); - method public static android.renderscript.Element MATRIX_4X4(android.renderscript.RenderScript); - method public static android.renderscript.Element MESH(android.renderscript.RenderScript); - method public static android.renderscript.Element PROGRAM_FRAGMENT(android.renderscript.RenderScript); - method public static android.renderscript.Element PROGRAM_RASTER(android.renderscript.RenderScript); - method public static android.renderscript.Element PROGRAM_STORE(android.renderscript.RenderScript); - method public static android.renderscript.Element PROGRAM_VERTEX(android.renderscript.RenderScript); - method public static android.renderscript.Element RGBA_4444(android.renderscript.RenderScript); - method public static android.renderscript.Element RGBA_5551(android.renderscript.RenderScript); - method public static android.renderscript.Element RGBA_8888(android.renderscript.RenderScript); - method public static android.renderscript.Element RGB_565(android.renderscript.RenderScript); - method public static android.renderscript.Element RGB_888(android.renderscript.RenderScript); - method public static android.renderscript.Element SAMPLER(android.renderscript.RenderScript); - method public static android.renderscript.Element SCRIPT(android.renderscript.RenderScript); - method public static android.renderscript.Element TYPE(android.renderscript.RenderScript); - method public static android.renderscript.Element U16(android.renderscript.RenderScript); - method public static android.renderscript.Element U16_2(android.renderscript.RenderScript); - method public static android.renderscript.Element U16_3(android.renderscript.RenderScript); - method public static android.renderscript.Element U16_4(android.renderscript.RenderScript); - method public static android.renderscript.Element U32(android.renderscript.RenderScript); - method public static android.renderscript.Element U32_2(android.renderscript.RenderScript); - method public static android.renderscript.Element U32_3(android.renderscript.RenderScript); - method public static android.renderscript.Element U32_4(android.renderscript.RenderScript); - method public static android.renderscript.Element U64(android.renderscript.RenderScript); - method public static android.renderscript.Element U64_2(android.renderscript.RenderScript); - method public static android.renderscript.Element U64_3(android.renderscript.RenderScript); - method public static android.renderscript.Element U64_4(android.renderscript.RenderScript); - method public static android.renderscript.Element U8(android.renderscript.RenderScript); - method public static android.renderscript.Element U8_2(android.renderscript.RenderScript); - method public static android.renderscript.Element U8_3(android.renderscript.RenderScript); - method public static android.renderscript.Element U8_4(android.renderscript.RenderScript); - method public static android.renderscript.Element YUV(android.renderscript.RenderScript); - method public static android.renderscript.Element createPixel(android.renderscript.RenderScript, android.renderscript.Element.DataType, android.renderscript.Element.DataKind); - method public static android.renderscript.Element createVector(android.renderscript.RenderScript, android.renderscript.Element.DataType, int); - method public int getBytesSize(); - method public android.renderscript.Element.DataKind getDataKind(); - method public android.renderscript.Element.DataType getDataType(); - method public android.renderscript.Element getSubElement(int); - method public int getSubElementArraySize(int); - method public int getSubElementCount(); - method public String getSubElementName(int); - method public int getSubElementOffsetBytes(int); - method public int getVectorSize(); - method public boolean isCompatible(android.renderscript.Element); - method public boolean isComplex(); - } - - public static class Element.Builder { - ctor public Element.Builder(android.renderscript.RenderScript); - method public android.renderscript.Element.Builder add(android.renderscript.Element, String, int); - method public android.renderscript.Element.Builder add(android.renderscript.Element, String); - method public android.renderscript.Element create(); - } - - public enum Element.DataKind { - enum_constant public static final android.renderscript.Element.DataKind PIXEL_A; - enum_constant public static final android.renderscript.Element.DataKind PIXEL_DEPTH; - enum_constant public static final android.renderscript.Element.DataKind PIXEL_L; - enum_constant public static final android.renderscript.Element.DataKind PIXEL_LA; - enum_constant public static final android.renderscript.Element.DataKind PIXEL_RGB; - enum_constant public static final android.renderscript.Element.DataKind PIXEL_RGBA; - enum_constant public static final android.renderscript.Element.DataKind PIXEL_YUV; - enum_constant public static final android.renderscript.Element.DataKind USER; - } - - public enum Element.DataType { - enum_constant public static final android.renderscript.Element.DataType BOOLEAN; - enum_constant public static final android.renderscript.Element.DataType FLOAT_16; - enum_constant public static final android.renderscript.Element.DataType FLOAT_32; - enum_constant public static final android.renderscript.Element.DataType FLOAT_64; - enum_constant public static final android.renderscript.Element.DataType MATRIX_2X2; - enum_constant public static final android.renderscript.Element.DataType MATRIX_3X3; - enum_constant public static final android.renderscript.Element.DataType MATRIX_4X4; - enum_constant public static final android.renderscript.Element.DataType NONE; - enum_constant public static final android.renderscript.Element.DataType RS_ALLOCATION; - enum_constant public static final android.renderscript.Element.DataType RS_ELEMENT; - enum_constant public static final android.renderscript.Element.DataType RS_FONT; - enum_constant public static final android.renderscript.Element.DataType RS_MESH; - enum_constant public static final android.renderscript.Element.DataType RS_PROGRAM_FRAGMENT; - enum_constant public static final android.renderscript.Element.DataType RS_PROGRAM_RASTER; - enum_constant public static final android.renderscript.Element.DataType RS_PROGRAM_STORE; - enum_constant public static final android.renderscript.Element.DataType RS_PROGRAM_VERTEX; - enum_constant public static final android.renderscript.Element.DataType RS_SAMPLER; - enum_constant public static final android.renderscript.Element.DataType RS_SCRIPT; - enum_constant public static final android.renderscript.Element.DataType RS_TYPE; - enum_constant public static final android.renderscript.Element.DataType SIGNED_16; - enum_constant public static final android.renderscript.Element.DataType SIGNED_32; - enum_constant public static final android.renderscript.Element.DataType SIGNED_64; - enum_constant public static final android.renderscript.Element.DataType SIGNED_8; - enum_constant public static final android.renderscript.Element.DataType UNSIGNED_16; - enum_constant public static final android.renderscript.Element.DataType UNSIGNED_32; - enum_constant public static final android.renderscript.Element.DataType UNSIGNED_4_4_4_4; - enum_constant public static final android.renderscript.Element.DataType UNSIGNED_5_5_5_1; - enum_constant public static final android.renderscript.Element.DataType UNSIGNED_5_6_5; - enum_constant public static final android.renderscript.Element.DataType UNSIGNED_64; - enum_constant public static final android.renderscript.Element.DataType UNSIGNED_8; - } - - public class FieldPacker { - ctor public FieldPacker(int); - ctor public FieldPacker(byte[]); - method public void addBoolean(boolean); - method public void addF32(float); - method public void addF32(android.renderscript.Float2); - method public void addF32(android.renderscript.Float3); - method public void addF32(android.renderscript.Float4); - method public void addF64(double); - method public void addF64(android.renderscript.Double2); - method public void addF64(android.renderscript.Double3); - method public void addF64(android.renderscript.Double4); - method public void addI16(short); - method public void addI16(android.renderscript.Short2); - method public void addI16(android.renderscript.Short3); - method public void addI16(android.renderscript.Short4); - method public void addI32(int); - method public void addI32(android.renderscript.Int2); - method public void addI32(android.renderscript.Int3); - method public void addI32(android.renderscript.Int4); - method public void addI64(long); - method public void addI64(android.renderscript.Long2); - method public void addI64(android.renderscript.Long3); - method public void addI64(android.renderscript.Long4); - method public void addI8(byte); - method public void addI8(android.renderscript.Byte2); - method public void addI8(android.renderscript.Byte3); - method public void addI8(android.renderscript.Byte4); - method public void addMatrix(android.renderscript.Matrix4f); - method public void addMatrix(android.renderscript.Matrix3f); - method public void addMatrix(android.renderscript.Matrix2f); - method public void addObj(android.renderscript.BaseObj); - method public void addU16(int); - method public void addU16(android.renderscript.Int2); - method public void addU16(android.renderscript.Int3); - method public void addU16(android.renderscript.Int4); - method public void addU32(long); - method public void addU32(android.renderscript.Long2); - method public void addU32(android.renderscript.Long3); - method public void addU32(android.renderscript.Long4); - method public void addU64(long); - method public void addU64(android.renderscript.Long2); - method public void addU64(android.renderscript.Long3); - method public void addU64(android.renderscript.Long4); - method public void addU8(short); - method public void addU8(android.renderscript.Short2); - method public void addU8(android.renderscript.Short3); - method public void addU8(android.renderscript.Short4); - method public void align(int); - method public final byte[] getData(); - method public void reset(); - method public void reset(int); - method public void skip(int); - method public boolean subBoolean(); - method public android.renderscript.Byte2 subByte2(); - method public android.renderscript.Byte3 subByte3(); - method public android.renderscript.Byte4 subByte4(); - method public android.renderscript.Double2 subDouble2(); - method public android.renderscript.Double3 subDouble3(); - method public android.renderscript.Double4 subDouble4(); - method public float subF32(); - method public double subF64(); - method public android.renderscript.Float2 subFloat2(); - method public android.renderscript.Float3 subFloat3(); - method public android.renderscript.Float4 subFloat4(); - method public short subI16(); - method public int subI32(); - method public long subI64(); - method public byte subI8(); - method public android.renderscript.Int2 subInt2(); - method public android.renderscript.Int3 subInt3(); - method public android.renderscript.Int4 subInt4(); - method public android.renderscript.Long2 subLong2(); - method public android.renderscript.Long3 subLong3(); - method public android.renderscript.Long4 subLong4(); - method public android.renderscript.Matrix2f subMatrix2f(); - method public android.renderscript.Matrix3f subMatrix3f(); - method public android.renderscript.Matrix4f subMatrix4f(); - method public android.renderscript.Short2 subShort2(); - method public android.renderscript.Short3 subShort3(); - method public android.renderscript.Short4 subShort4(); - method public void subalign(int); - } - - public class Float2 { - ctor public Float2(); - ctor public Float2(float, float); - field public float x; - field public float y; - } - - public class Float3 { - ctor public Float3(); - ctor public Float3(float, float, float); - field public float x; - field public float y; - field public float z; - } - - public class Float4 { - ctor public Float4(); - ctor public Float4(float, float, float, float); - field public float w; - field public float x; - field public float y; - field public float z; - } - - public class Int2 { - ctor public Int2(); - ctor public Int2(int, int); - field public int x; - field public int y; - } - - public class Int3 { - ctor public Int3(); - ctor public Int3(int, int, int); - field public int x; - field public int y; - field public int z; - } - - public class Int4 { - ctor public Int4(); - ctor public Int4(int, int, int, int); - field public int w; - field public int x; - field public int y; - field public int z; - } - - public class Long2 { - ctor public Long2(); - ctor public Long2(long, long); - field public long x; - field public long y; - } - - public class Long3 { - ctor public Long3(); - ctor public Long3(long, long, long); - field public long x; - field public long y; - field public long z; - } - - public class Long4 { - ctor public Long4(); - ctor public Long4(long, long, long, long); - field public long w; - field public long x; - field public long y; - field public long z; - } - - public class Matrix2f { - ctor public Matrix2f(); - ctor public Matrix2f(float[]); - method public float get(int, int); - method public float[] getArray(); - method public void load(android.renderscript.Matrix2f); - method public void loadIdentity(); - method public void loadMultiply(android.renderscript.Matrix2f, android.renderscript.Matrix2f); - method public void loadRotate(float); - method public void loadScale(float, float); - method public void multiply(android.renderscript.Matrix2f); - method public void rotate(float); - method public void scale(float, float); - method public void set(int, int, float); - method public void transpose(); - } - - public class Matrix3f { - ctor public Matrix3f(); - ctor public Matrix3f(float[]); - method public float get(int, int); - method public float[] getArray(); - method public void load(android.renderscript.Matrix3f); - method public void loadIdentity(); - method public void loadMultiply(android.renderscript.Matrix3f, android.renderscript.Matrix3f); - method public void loadRotate(float, float, float, float); - method public void loadRotate(float); - method public void loadScale(float, float); - method public void loadScale(float, float, float); - method public void loadTranslate(float, float); - method public void multiply(android.renderscript.Matrix3f); - method public void rotate(float, float, float, float); - method public void rotate(float); - method public void scale(float, float); - method public void scale(float, float, float); - method public void set(int, int, float); - method public void translate(float, float); - method public void transpose(); - } - - public class Matrix4f { - ctor public Matrix4f(); - ctor public Matrix4f(float[]); - method public float get(int, int); - method public float[] getArray(); - method public boolean inverse(); - method public boolean inverseTranspose(); - method public void load(android.renderscript.Matrix4f); - method public void loadFrustum(float, float, float, float, float, float); - method public void loadIdentity(); - method public void loadMultiply(android.renderscript.Matrix4f, android.renderscript.Matrix4f); - method public void loadOrtho(float, float, float, float, float, float); - method public void loadOrthoWindow(int, int); - method public void loadPerspective(float, float, float, float); - method public void loadProjectionNormalized(int, int); - method public void loadRotate(float, float, float, float); - method public void loadScale(float, float, float); - method public void loadTranslate(float, float, float); - method public void multiply(android.renderscript.Matrix4f); - method public void rotate(float, float, float, float); - method public void scale(float, float, float); - method public void set(int, int, float); - method public void translate(float, float, float); - method public void transpose(); - } - - public class RSDriverException extends android.renderscript.RSRuntimeException { - ctor public RSDriverException(String); - } - - public class RSIllegalArgumentException extends android.renderscript.RSRuntimeException { - ctor public RSIllegalArgumentException(String); - } - - public class RSInvalidStateException extends android.renderscript.RSRuntimeException { - ctor public RSInvalidStateException(String); - } - - public class RSRuntimeException extends java.lang.RuntimeException { - ctor public RSRuntimeException(String); - } - - public class RenderScript { - method public void contextDump(); - method public static android.renderscript.RenderScript create(android.content.Context); - method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType); - method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType, int); - method public static android.renderscript.RenderScript createMultiContext(android.content.Context, android.renderscript.RenderScript.ContextType, int, int); - method public void destroy(); - method public void finish(); - method public final android.content.Context getApplicationContext(); - method public android.renderscript.RenderScript.RSErrorHandler getErrorHandler(); - method public android.renderscript.RenderScript.RSMessageHandler getMessageHandler(); - method public static long getMinorVersion(); - method public static void releaseAllContexts(); - method public void sendMessage(int, int[]); - method public void setErrorHandler(android.renderscript.RenderScript.RSErrorHandler); - method public void setMessageHandler(android.renderscript.RenderScript.RSMessageHandler); - method public void setPriority(android.renderscript.RenderScript.Priority); - field public static final int CREATE_FLAG_LOW_LATENCY = 2; // 0x2 - field public static final int CREATE_FLAG_LOW_POWER = 4; // 0x4 - field public static final int CREATE_FLAG_NONE = 0; // 0x0 - } - - public enum RenderScript.ContextType { - enum_constant public static final android.renderscript.RenderScript.ContextType DEBUG; - enum_constant public static final android.renderscript.RenderScript.ContextType NORMAL; - enum_constant public static final android.renderscript.RenderScript.ContextType PROFILE; - } - - public enum RenderScript.Priority { - enum_constant public static final android.renderscript.RenderScript.Priority LOW; - enum_constant public static final android.renderscript.RenderScript.Priority NORMAL; - } - - public static class RenderScript.RSErrorHandler implements java.lang.Runnable { - ctor public RenderScript.RSErrorHandler(); - method public void run(); - field protected String mErrorMessage; - field protected int mErrorNum; - } - - public static class RenderScript.RSMessageHandler implements java.lang.Runnable { - ctor public RenderScript.RSMessageHandler(); - method public void run(); - field protected int[] mData; - field protected int mID; - field protected int mLength; - } - - public class Sampler extends android.renderscript.BaseObj { - method public static android.renderscript.Sampler CLAMP_LINEAR(android.renderscript.RenderScript); - method public static android.renderscript.Sampler CLAMP_LINEAR_MIP_LINEAR(android.renderscript.RenderScript); - method public static android.renderscript.Sampler CLAMP_NEAREST(android.renderscript.RenderScript); - method public static android.renderscript.Sampler MIRRORED_REPEAT_LINEAR(android.renderscript.RenderScript); - method public static android.renderscript.Sampler MIRRORED_REPEAT_LINEAR_MIP_LINEAR(android.renderscript.RenderScript); - method public static android.renderscript.Sampler MIRRORED_REPEAT_NEAREST(android.renderscript.RenderScript); - method public static android.renderscript.Sampler WRAP_LINEAR(android.renderscript.RenderScript); - method public static android.renderscript.Sampler WRAP_LINEAR_MIP_LINEAR(android.renderscript.RenderScript); - method public static android.renderscript.Sampler WRAP_NEAREST(android.renderscript.RenderScript); - method public float getAnisotropy(); - method public android.renderscript.Sampler.Value getMagnification(); - method public android.renderscript.Sampler.Value getMinification(); - method public android.renderscript.Sampler.Value getWrapS(); - method public android.renderscript.Sampler.Value getWrapT(); - } - - public static class Sampler.Builder { - ctor public Sampler.Builder(android.renderscript.RenderScript); - method public android.renderscript.Sampler create(); - method public void setAnisotropy(float); - method public void setMagnification(android.renderscript.Sampler.Value); - method public void setMinification(android.renderscript.Sampler.Value); - method public void setWrapS(android.renderscript.Sampler.Value); - method public void setWrapT(android.renderscript.Sampler.Value); - } - - public enum Sampler.Value { - enum_constant public static final android.renderscript.Sampler.Value CLAMP; - enum_constant public static final android.renderscript.Sampler.Value LINEAR; - enum_constant public static final android.renderscript.Sampler.Value LINEAR_MIP_LINEAR; - enum_constant public static final android.renderscript.Sampler.Value LINEAR_MIP_NEAREST; - enum_constant public static final android.renderscript.Sampler.Value MIRRORED_REPEAT; - enum_constant public static final android.renderscript.Sampler.Value NEAREST; - enum_constant public static final android.renderscript.Sampler.Value WRAP; - } - - public class Script extends android.renderscript.BaseObj { - method public void bindAllocation(android.renderscript.Allocation, int); - method protected android.renderscript.Script.FieldID createFieldID(int, android.renderscript.Element); - method protected android.renderscript.Script.InvokeID createInvokeID(int); - method protected android.renderscript.Script.KernelID createKernelID(int, int, android.renderscript.Element, android.renderscript.Element); - method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker); - method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker, android.renderscript.Script.LaunchOptions); - method protected void forEach(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.FieldPacker); - method protected void forEach(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.FieldPacker, android.renderscript.Script.LaunchOptions); - method public boolean getVarB(int); - method public double getVarD(int); - method public float getVarF(int); - method public int getVarI(int); - method public long getVarJ(int); - method public void getVarV(int, android.renderscript.FieldPacker); - method protected void invoke(int); - method protected void invoke(int, android.renderscript.FieldPacker); - method protected void reduce(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void setTimeZone(String); - method public void setVar(int, float); - method public void setVar(int, double); - method public void setVar(int, int); - method public void setVar(int, long); - method public void setVar(int, boolean); - method public void setVar(int, android.renderscript.BaseObj); - method public void setVar(int, android.renderscript.FieldPacker); - method public void setVar(int, android.renderscript.FieldPacker, android.renderscript.Element, int[]); - } - - public static class Script.Builder { - } - - public static class Script.FieldBase { - ctor protected Script.FieldBase(); - method public android.renderscript.Allocation getAllocation(); - method public android.renderscript.Element getElement(); - method public android.renderscript.Type getType(); - method protected void init(android.renderscript.RenderScript, int); - method protected void init(android.renderscript.RenderScript, int, int); - method public void updateAllocation(); - field protected android.renderscript.Allocation mAllocation; - field protected android.renderscript.Element mElement; - } - - public static final class Script.FieldID extends android.renderscript.BaseObj { - } - - public static final class Script.InvokeID extends android.renderscript.BaseObj { - } - - public static final class Script.KernelID extends android.renderscript.BaseObj { + method @Deprecated public static android.renderscript.Element MATRIX_2X2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element MATRIX_3X3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element MATRIX_4X4(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element MESH(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element PROGRAM_FRAGMENT(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element PROGRAM_RASTER(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element PROGRAM_STORE(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element PROGRAM_VERTEX(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element RGBA_4444(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element RGBA_5551(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element RGBA_8888(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element RGB_565(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element RGB_888(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element SAMPLER(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element SCRIPT(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element TYPE(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U16(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U16_2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U16_3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U16_4(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U32(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U32_2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U32_3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U32_4(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U64(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U64_2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U64_3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U64_4(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U8(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U8_2(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U8_3(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element U8_4(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element YUV(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Element createPixel(android.renderscript.RenderScript, android.renderscript.Element.DataType, android.renderscript.Element.DataKind); + method @Deprecated public static android.renderscript.Element createVector(android.renderscript.RenderScript, android.renderscript.Element.DataType, int); + method @Deprecated public int getBytesSize(); + method @Deprecated public android.renderscript.Element.DataKind getDataKind(); + method @Deprecated public android.renderscript.Element.DataType getDataType(); + method @Deprecated public android.renderscript.Element getSubElement(int); + method @Deprecated public int getSubElementArraySize(int); + method @Deprecated public int getSubElementCount(); + method @Deprecated public String getSubElementName(int); + method @Deprecated public int getSubElementOffsetBytes(int); + method @Deprecated public int getVectorSize(); + method @Deprecated public boolean isCompatible(android.renderscript.Element); + method @Deprecated public boolean isComplex(); + } + + @Deprecated public static class Element.Builder { + ctor @Deprecated public Element.Builder(android.renderscript.RenderScript); + method @Deprecated public android.renderscript.Element.Builder add(android.renderscript.Element, String, int); + method @Deprecated public android.renderscript.Element.Builder add(android.renderscript.Element, String); + method @Deprecated public android.renderscript.Element create(); + } + + @Deprecated public enum Element.DataKind { + enum_constant @Deprecated public static final android.renderscript.Element.DataKind PIXEL_A; + enum_constant @Deprecated public static final android.renderscript.Element.DataKind PIXEL_DEPTH; + enum_constant @Deprecated public static final android.renderscript.Element.DataKind PIXEL_L; + enum_constant @Deprecated public static final android.renderscript.Element.DataKind PIXEL_LA; + enum_constant @Deprecated public static final android.renderscript.Element.DataKind PIXEL_RGB; + enum_constant @Deprecated public static final android.renderscript.Element.DataKind PIXEL_RGBA; + enum_constant @Deprecated public static final android.renderscript.Element.DataKind PIXEL_YUV; + enum_constant @Deprecated public static final android.renderscript.Element.DataKind USER; + } + + @Deprecated public enum Element.DataType { + enum_constant @Deprecated public static final android.renderscript.Element.DataType BOOLEAN; + enum_constant @Deprecated public static final android.renderscript.Element.DataType FLOAT_16; + enum_constant @Deprecated public static final android.renderscript.Element.DataType FLOAT_32; + enum_constant @Deprecated public static final android.renderscript.Element.DataType FLOAT_64; + enum_constant @Deprecated public static final android.renderscript.Element.DataType MATRIX_2X2; + enum_constant @Deprecated public static final android.renderscript.Element.DataType MATRIX_3X3; + enum_constant @Deprecated public static final android.renderscript.Element.DataType MATRIX_4X4; + enum_constant @Deprecated public static final android.renderscript.Element.DataType NONE; + enum_constant @Deprecated public static final android.renderscript.Element.DataType RS_ALLOCATION; + enum_constant @Deprecated public static final android.renderscript.Element.DataType RS_ELEMENT; + enum_constant @Deprecated public static final android.renderscript.Element.DataType RS_FONT; + enum_constant @Deprecated public static final android.renderscript.Element.DataType RS_MESH; + enum_constant @Deprecated public static final android.renderscript.Element.DataType RS_PROGRAM_FRAGMENT; + enum_constant @Deprecated public static final android.renderscript.Element.DataType RS_PROGRAM_RASTER; + enum_constant @Deprecated public static final android.renderscript.Element.DataType RS_PROGRAM_STORE; + enum_constant @Deprecated public static final android.renderscript.Element.DataType RS_PROGRAM_VERTEX; + enum_constant @Deprecated public static final android.renderscript.Element.DataType RS_SAMPLER; + enum_constant @Deprecated public static final android.renderscript.Element.DataType RS_SCRIPT; + enum_constant @Deprecated public static final android.renderscript.Element.DataType RS_TYPE; + enum_constant @Deprecated public static final android.renderscript.Element.DataType SIGNED_16; + enum_constant @Deprecated public static final android.renderscript.Element.DataType SIGNED_32; + enum_constant @Deprecated public static final android.renderscript.Element.DataType SIGNED_64; + enum_constant @Deprecated public static final android.renderscript.Element.DataType SIGNED_8; + enum_constant @Deprecated public static final android.renderscript.Element.DataType UNSIGNED_16; + enum_constant @Deprecated public static final android.renderscript.Element.DataType UNSIGNED_32; + enum_constant @Deprecated public static final android.renderscript.Element.DataType UNSIGNED_4_4_4_4; + enum_constant @Deprecated public static final android.renderscript.Element.DataType UNSIGNED_5_5_5_1; + enum_constant @Deprecated public static final android.renderscript.Element.DataType UNSIGNED_5_6_5; + enum_constant @Deprecated public static final android.renderscript.Element.DataType UNSIGNED_64; + enum_constant @Deprecated public static final android.renderscript.Element.DataType UNSIGNED_8; + } + + @Deprecated public class FieldPacker { + ctor @Deprecated public FieldPacker(int); + ctor @Deprecated public FieldPacker(byte[]); + method @Deprecated public void addBoolean(boolean); + method @Deprecated public void addF32(float); + method @Deprecated public void addF32(android.renderscript.Float2); + method @Deprecated public void addF32(android.renderscript.Float3); + method @Deprecated public void addF32(android.renderscript.Float4); + method @Deprecated public void addF64(double); + method @Deprecated public void addF64(android.renderscript.Double2); + method @Deprecated public void addF64(android.renderscript.Double3); + method @Deprecated public void addF64(android.renderscript.Double4); + method @Deprecated public void addI16(short); + method @Deprecated public void addI16(android.renderscript.Short2); + method @Deprecated public void addI16(android.renderscript.Short3); + method @Deprecated public void addI16(android.renderscript.Short4); + method @Deprecated public void addI32(int); + method @Deprecated public void addI32(android.renderscript.Int2); + method @Deprecated public void addI32(android.renderscript.Int3); + method @Deprecated public void addI32(android.renderscript.Int4); + method @Deprecated public void addI64(long); + method @Deprecated public void addI64(android.renderscript.Long2); + method @Deprecated public void addI64(android.renderscript.Long3); + method @Deprecated public void addI64(android.renderscript.Long4); + method @Deprecated public void addI8(byte); + method @Deprecated public void addI8(android.renderscript.Byte2); + method @Deprecated public void addI8(android.renderscript.Byte3); + method @Deprecated public void addI8(android.renderscript.Byte4); + method @Deprecated public void addMatrix(android.renderscript.Matrix4f); + method @Deprecated public void addMatrix(android.renderscript.Matrix3f); + method @Deprecated public void addMatrix(android.renderscript.Matrix2f); + method @Deprecated public void addObj(android.renderscript.BaseObj); + method @Deprecated public void addU16(int); + method @Deprecated public void addU16(android.renderscript.Int2); + method @Deprecated public void addU16(android.renderscript.Int3); + method @Deprecated public void addU16(android.renderscript.Int4); + method @Deprecated public void addU32(long); + method @Deprecated public void addU32(android.renderscript.Long2); + method @Deprecated public void addU32(android.renderscript.Long3); + method @Deprecated public void addU32(android.renderscript.Long4); + method @Deprecated public void addU64(long); + method @Deprecated public void addU64(android.renderscript.Long2); + method @Deprecated public void addU64(android.renderscript.Long3); + method @Deprecated public void addU64(android.renderscript.Long4); + method @Deprecated public void addU8(short); + method @Deprecated public void addU8(android.renderscript.Short2); + method @Deprecated public void addU8(android.renderscript.Short3); + method @Deprecated public void addU8(android.renderscript.Short4); + method @Deprecated public void align(int); + method @Deprecated public final byte[] getData(); + method @Deprecated public void reset(); + method @Deprecated public void reset(int); + method @Deprecated public void skip(int); + method @Deprecated public boolean subBoolean(); + method @Deprecated public android.renderscript.Byte2 subByte2(); + method @Deprecated public android.renderscript.Byte3 subByte3(); + method @Deprecated public android.renderscript.Byte4 subByte4(); + method @Deprecated public android.renderscript.Double2 subDouble2(); + method @Deprecated public android.renderscript.Double3 subDouble3(); + method @Deprecated public android.renderscript.Double4 subDouble4(); + method @Deprecated public float subF32(); + method @Deprecated public double subF64(); + method @Deprecated public android.renderscript.Float2 subFloat2(); + method @Deprecated public android.renderscript.Float3 subFloat3(); + method @Deprecated public android.renderscript.Float4 subFloat4(); + method @Deprecated public short subI16(); + method @Deprecated public int subI32(); + method @Deprecated public long subI64(); + method @Deprecated public byte subI8(); + method @Deprecated public android.renderscript.Int2 subInt2(); + method @Deprecated public android.renderscript.Int3 subInt3(); + method @Deprecated public android.renderscript.Int4 subInt4(); + method @Deprecated public android.renderscript.Long2 subLong2(); + method @Deprecated public android.renderscript.Long3 subLong3(); + method @Deprecated public android.renderscript.Long4 subLong4(); + method @Deprecated public android.renderscript.Matrix2f subMatrix2f(); + method @Deprecated public android.renderscript.Matrix3f subMatrix3f(); + method @Deprecated public android.renderscript.Matrix4f subMatrix4f(); + method @Deprecated public android.renderscript.Short2 subShort2(); + method @Deprecated public android.renderscript.Short3 subShort3(); + method @Deprecated public android.renderscript.Short4 subShort4(); + method @Deprecated public void subalign(int); + } + + @Deprecated public class Float2 { + ctor @Deprecated public Float2(); + ctor @Deprecated public Float2(float, float); + field @Deprecated public float x; + field @Deprecated public float y; + } + + @Deprecated public class Float3 { + ctor @Deprecated public Float3(); + ctor @Deprecated public Float3(float, float, float); + field @Deprecated public float x; + field @Deprecated public float y; + field @Deprecated public float z; + } + + @Deprecated public class Float4 { + ctor @Deprecated public Float4(); + ctor @Deprecated public Float4(float, float, float, float); + field @Deprecated public float w; + field @Deprecated public float x; + field @Deprecated public float y; + field @Deprecated public float z; + } + + @Deprecated public class Int2 { + ctor @Deprecated public Int2(); + ctor @Deprecated public Int2(int, int); + field @Deprecated public int x; + field @Deprecated public int y; } - public static final class Script.LaunchOptions { - ctor public Script.LaunchOptions(); - method public int getXEnd(); - method public int getXStart(); - method public int getYEnd(); - method public int getYStart(); - method public int getZEnd(); - method public int getZStart(); - method public android.renderscript.Script.LaunchOptions setX(int, int); - method public android.renderscript.Script.LaunchOptions setY(int, int); - method public android.renderscript.Script.LaunchOptions setZ(int, int); + @Deprecated public class Int3 { + ctor @Deprecated public Int3(); + ctor @Deprecated public Int3(int, int, int); + field @Deprecated public int x; + field @Deprecated public int y; + field @Deprecated public int z; } - public class ScriptC extends android.renderscript.Script { - ctor protected ScriptC(int, android.renderscript.RenderScript); - ctor protected ScriptC(long, android.renderscript.RenderScript); - ctor protected ScriptC(android.renderscript.RenderScript, android.content.res.Resources, int); - ctor protected ScriptC(android.renderscript.RenderScript, String, byte[], byte[]); + @Deprecated public class Int4 { + ctor @Deprecated public Int4(); + ctor @Deprecated public Int4(int, int, int, int); + field @Deprecated public int w; + field @Deprecated public int x; + field @Deprecated public int y; + field @Deprecated public int z; + } + + @Deprecated public class Long2 { + ctor @Deprecated public Long2(); + ctor @Deprecated public Long2(long, long); + field @Deprecated public long x; + field @Deprecated public long y; + } + + @Deprecated public class Long3 { + ctor @Deprecated public Long3(); + ctor @Deprecated public Long3(long, long, long); + field @Deprecated public long x; + field @Deprecated public long y; + field @Deprecated public long z; + } + + @Deprecated public class Long4 { + ctor @Deprecated public Long4(); + ctor @Deprecated public Long4(long, long, long, long); + field @Deprecated public long w; + field @Deprecated public long x; + field @Deprecated public long y; + field @Deprecated public long z; + } + + @Deprecated public class Matrix2f { + ctor @Deprecated public Matrix2f(); + ctor @Deprecated public Matrix2f(float[]); + method @Deprecated public float get(int, int); + method @Deprecated public float[] getArray(); + method @Deprecated public void load(android.renderscript.Matrix2f); + method @Deprecated public void loadIdentity(); + method @Deprecated public void loadMultiply(android.renderscript.Matrix2f, android.renderscript.Matrix2f); + method @Deprecated public void loadRotate(float); + method @Deprecated public void loadScale(float, float); + method @Deprecated public void multiply(android.renderscript.Matrix2f); + method @Deprecated public void rotate(float); + method @Deprecated public void scale(float, float); + method @Deprecated public void set(int, int, float); + method @Deprecated public void transpose(); + } + + @Deprecated public class Matrix3f { + ctor @Deprecated public Matrix3f(); + ctor @Deprecated public Matrix3f(float[]); + method @Deprecated public float get(int, int); + method @Deprecated public float[] getArray(); + method @Deprecated public void load(android.renderscript.Matrix3f); + method @Deprecated public void loadIdentity(); + method @Deprecated public void loadMultiply(android.renderscript.Matrix3f, android.renderscript.Matrix3f); + method @Deprecated public void loadRotate(float, float, float, float); + method @Deprecated public void loadRotate(float); + method @Deprecated public void loadScale(float, float); + method @Deprecated public void loadScale(float, float, float); + method @Deprecated public void loadTranslate(float, float); + method @Deprecated public void multiply(android.renderscript.Matrix3f); + method @Deprecated public void rotate(float, float, float, float); + method @Deprecated public void rotate(float); + method @Deprecated public void scale(float, float); + method @Deprecated public void scale(float, float, float); + method @Deprecated public void set(int, int, float); + method @Deprecated public void translate(float, float); + method @Deprecated public void transpose(); + } + + @Deprecated public class Matrix4f { + ctor @Deprecated public Matrix4f(); + ctor @Deprecated public Matrix4f(float[]); + method @Deprecated public float get(int, int); + method @Deprecated public float[] getArray(); + method @Deprecated public boolean inverse(); + method @Deprecated public boolean inverseTranspose(); + method @Deprecated public void load(android.renderscript.Matrix4f); + method @Deprecated public void loadFrustum(float, float, float, float, float, float); + method @Deprecated public void loadIdentity(); + method @Deprecated public void loadMultiply(android.renderscript.Matrix4f, android.renderscript.Matrix4f); + method @Deprecated public void loadOrtho(float, float, float, float, float, float); + method @Deprecated public void loadOrthoWindow(int, int); + method @Deprecated public void loadPerspective(float, float, float, float); + method @Deprecated public void loadProjectionNormalized(int, int); + method @Deprecated public void loadRotate(float, float, float, float); + method @Deprecated public void loadScale(float, float, float); + method @Deprecated public void loadTranslate(float, float, float); + method @Deprecated public void multiply(android.renderscript.Matrix4f); + method @Deprecated public void rotate(float, float, float, float); + method @Deprecated public void scale(float, float, float); + method @Deprecated public void set(int, int, float); + method @Deprecated public void translate(float, float, float); + method @Deprecated public void transpose(); + } + + @Deprecated public class RSDriverException extends android.renderscript.RSRuntimeException { + ctor @Deprecated public RSDriverException(String); + } + + @Deprecated public class RSIllegalArgumentException extends android.renderscript.RSRuntimeException { + ctor @Deprecated public RSIllegalArgumentException(String); + } + + @Deprecated public class RSInvalidStateException extends android.renderscript.RSRuntimeException { + ctor @Deprecated public RSInvalidStateException(String); + } + + @Deprecated public class RSRuntimeException extends java.lang.RuntimeException { + ctor @Deprecated public RSRuntimeException(String); + } + + @Deprecated public class RenderScript { + method @Deprecated public void contextDump(); + method @Deprecated public static android.renderscript.RenderScript create(android.content.Context); + method @Deprecated public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType); + method @Deprecated public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType, int); + method @Deprecated public static android.renderscript.RenderScript createMultiContext(android.content.Context, android.renderscript.RenderScript.ContextType, int, int); + method @Deprecated public void destroy(); + method @Deprecated public void finish(); + method @Deprecated public final android.content.Context getApplicationContext(); + method @Deprecated public android.renderscript.RenderScript.RSErrorHandler getErrorHandler(); + method @Deprecated public android.renderscript.RenderScript.RSMessageHandler getMessageHandler(); + method @Deprecated public static long getMinorVersion(); + method @Deprecated public static void releaseAllContexts(); + method @Deprecated public void sendMessage(int, int[]); + method @Deprecated public void setErrorHandler(android.renderscript.RenderScript.RSErrorHandler); + method @Deprecated public void setMessageHandler(android.renderscript.RenderScript.RSMessageHandler); + method @Deprecated public void setPriority(android.renderscript.RenderScript.Priority); + field @Deprecated public static final int CREATE_FLAG_LOW_LATENCY = 2; // 0x2 + field @Deprecated public static final int CREATE_FLAG_LOW_POWER = 4; // 0x4 + field @Deprecated public static final int CREATE_FLAG_NONE = 0; // 0x0 + } + + @Deprecated public enum RenderScript.ContextType { + enum_constant @Deprecated public static final android.renderscript.RenderScript.ContextType DEBUG; + enum_constant @Deprecated public static final android.renderscript.RenderScript.ContextType NORMAL; + enum_constant @Deprecated public static final android.renderscript.RenderScript.ContextType PROFILE; + } + + @Deprecated public enum RenderScript.Priority { + enum_constant @Deprecated public static final android.renderscript.RenderScript.Priority LOW; + enum_constant @Deprecated public static final android.renderscript.RenderScript.Priority NORMAL; + } + + @Deprecated public static class RenderScript.RSErrorHandler implements java.lang.Runnable { + ctor @Deprecated public RenderScript.RSErrorHandler(); + method @Deprecated public void run(); + field @Deprecated protected String mErrorMessage; + field @Deprecated protected int mErrorNum; } - public final class ScriptGroup extends android.renderscript.BaseObj { - method public Object[] execute(java.lang.Object...); + @Deprecated public static class RenderScript.RSMessageHandler implements java.lang.Runnable { + ctor @Deprecated public RenderScript.RSMessageHandler(); + method @Deprecated public void run(); + field @Deprecated protected int[] mData; + field @Deprecated protected int mID; + field @Deprecated protected int mLength; + } + + @Deprecated public class Sampler extends android.renderscript.BaseObj { + method @Deprecated public static android.renderscript.Sampler CLAMP_LINEAR(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Sampler CLAMP_LINEAR_MIP_LINEAR(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Sampler CLAMP_NEAREST(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Sampler MIRRORED_REPEAT_LINEAR(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Sampler MIRRORED_REPEAT_LINEAR_MIP_LINEAR(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Sampler MIRRORED_REPEAT_NEAREST(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Sampler WRAP_LINEAR(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Sampler WRAP_LINEAR_MIP_LINEAR(android.renderscript.RenderScript); + method @Deprecated public static android.renderscript.Sampler WRAP_NEAREST(android.renderscript.RenderScript); + method @Deprecated public float getAnisotropy(); + method @Deprecated public android.renderscript.Sampler.Value getMagnification(); + method @Deprecated public android.renderscript.Sampler.Value getMinification(); + method @Deprecated public android.renderscript.Sampler.Value getWrapS(); + method @Deprecated public android.renderscript.Sampler.Value getWrapT(); + } + + @Deprecated public static class Sampler.Builder { + ctor @Deprecated public Sampler.Builder(android.renderscript.RenderScript); + method @Deprecated public android.renderscript.Sampler create(); + method @Deprecated public void setAnisotropy(float); + method @Deprecated public void setMagnification(android.renderscript.Sampler.Value); + method @Deprecated public void setMinification(android.renderscript.Sampler.Value); + method @Deprecated public void setWrapS(android.renderscript.Sampler.Value); + method @Deprecated public void setWrapT(android.renderscript.Sampler.Value); + } + + @Deprecated public enum Sampler.Value { + enum_constant @Deprecated public static final android.renderscript.Sampler.Value CLAMP; + enum_constant @Deprecated public static final android.renderscript.Sampler.Value LINEAR; + enum_constant @Deprecated public static final android.renderscript.Sampler.Value LINEAR_MIP_LINEAR; + enum_constant @Deprecated public static final android.renderscript.Sampler.Value LINEAR_MIP_NEAREST; + enum_constant @Deprecated public static final android.renderscript.Sampler.Value MIRRORED_REPEAT; + enum_constant @Deprecated public static final android.renderscript.Sampler.Value NEAREST; + enum_constant @Deprecated public static final android.renderscript.Sampler.Value WRAP; + } + + @Deprecated public class Script extends android.renderscript.BaseObj { + method @Deprecated public void bindAllocation(android.renderscript.Allocation, int); + method @Deprecated protected android.renderscript.Script.FieldID createFieldID(int, android.renderscript.Element); + method @Deprecated protected android.renderscript.Script.InvokeID createInvokeID(int); + method @Deprecated protected android.renderscript.Script.KernelID createKernelID(int, int, android.renderscript.Element, android.renderscript.Element); + method @Deprecated protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker); + method @Deprecated protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker, android.renderscript.Script.LaunchOptions); + method @Deprecated protected void forEach(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.FieldPacker); + method @Deprecated protected void forEach(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.FieldPacker, android.renderscript.Script.LaunchOptions); + method @Deprecated public boolean getVarB(int); + method @Deprecated public double getVarD(int); + method @Deprecated public float getVarF(int); + method @Deprecated public int getVarI(int); + method @Deprecated public long getVarJ(int); + method @Deprecated public void getVarV(int, android.renderscript.FieldPacker); + method @Deprecated protected void invoke(int); + method @Deprecated protected void invoke(int, android.renderscript.FieldPacker); + method @Deprecated protected void reduce(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void setTimeZone(String); + method @Deprecated public void setVar(int, float); + method @Deprecated public void setVar(int, double); + method @Deprecated public void setVar(int, int); + method @Deprecated public void setVar(int, long); + method @Deprecated public void setVar(int, boolean); + method @Deprecated public void setVar(int, android.renderscript.BaseObj); + method @Deprecated public void setVar(int, android.renderscript.FieldPacker); + method @Deprecated public void setVar(int, android.renderscript.FieldPacker, android.renderscript.Element, int[]); + } + + @Deprecated public static class Script.Builder { + } + + @Deprecated public static class Script.FieldBase { + ctor @Deprecated protected Script.FieldBase(); + method @Deprecated public android.renderscript.Allocation getAllocation(); + method @Deprecated public android.renderscript.Element getElement(); + method @Deprecated public android.renderscript.Type getType(); + method @Deprecated protected void init(android.renderscript.RenderScript, int); + method @Deprecated protected void init(android.renderscript.RenderScript, int, int); + method @Deprecated public void updateAllocation(); + field @Deprecated protected android.renderscript.Allocation mAllocation; + field @Deprecated protected android.renderscript.Element mElement; + } + + @Deprecated public static final class Script.FieldID extends android.renderscript.BaseObj { + } + + @Deprecated public static final class Script.InvokeID extends android.renderscript.BaseObj { + } + + @Deprecated public static final class Script.KernelID extends android.renderscript.BaseObj { + } + + @Deprecated public static final class Script.LaunchOptions { + ctor @Deprecated public Script.LaunchOptions(); + method @Deprecated public int getXEnd(); + method @Deprecated public int getXStart(); + method @Deprecated public int getYEnd(); + method @Deprecated public int getYStart(); + method @Deprecated public int getZEnd(); + method @Deprecated public int getZStart(); + method @Deprecated public android.renderscript.Script.LaunchOptions setX(int, int); + method @Deprecated public android.renderscript.Script.LaunchOptions setY(int, int); + method @Deprecated public android.renderscript.Script.LaunchOptions setZ(int, int); + } + + @Deprecated public class ScriptC extends android.renderscript.Script { + ctor @Deprecated protected ScriptC(int, android.renderscript.RenderScript); + ctor @Deprecated protected ScriptC(long, android.renderscript.RenderScript); + ctor @Deprecated protected ScriptC(android.renderscript.RenderScript, android.content.res.Resources, int); + ctor @Deprecated protected ScriptC(android.renderscript.RenderScript, String, byte[], byte[]); + } + + @Deprecated public final class ScriptGroup extends android.renderscript.BaseObj { + method @Deprecated public Object[] execute(java.lang.Object...); method @Deprecated public void execute(); method @Deprecated public void setInput(android.renderscript.Script.KernelID, android.renderscript.Allocation); method @Deprecated public void setOutput(android.renderscript.Script.KernelID, android.renderscript.Allocation); } - public static final class ScriptGroup.Binding { - ctor public ScriptGroup.Binding(android.renderscript.Script.FieldID, Object); + @Deprecated public static final class ScriptGroup.Binding { + ctor @Deprecated public ScriptGroup.Binding(android.renderscript.Script.FieldID, Object); } @Deprecated public static final class ScriptGroup.Builder { @@ -36376,336 +36371,336 @@ package android.renderscript { method @Deprecated public android.renderscript.ScriptGroup create(); } - public static final class ScriptGroup.Builder2 { - ctor public ScriptGroup.Builder2(android.renderscript.RenderScript); - method public android.renderscript.ScriptGroup.Input addInput(); - method public android.renderscript.ScriptGroup.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object...); - method public android.renderscript.ScriptGroup.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object...); - method public android.renderscript.ScriptGroup create(String, android.renderscript.ScriptGroup.Future...); - } - - public static final class ScriptGroup.Closure extends android.renderscript.BaseObj { - method public android.renderscript.ScriptGroup.Future getGlobal(android.renderscript.Script.FieldID); - method public android.renderscript.ScriptGroup.Future getReturn(); - } - - public static final class ScriptGroup.Future { - } - - public static final class ScriptGroup.Input { - } - - public abstract class ScriptIntrinsic extends android.renderscript.Script { - } - - public final class ScriptIntrinsic3DLUT extends android.renderscript.ScriptIntrinsic { - method public static android.renderscript.ScriptIntrinsic3DLUT create(android.renderscript.RenderScript, android.renderscript.Element); - method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public android.renderscript.Script.KernelID getKernelID(); - method public void setLUT(android.renderscript.Allocation); - } - - public final class ScriptIntrinsicBLAS extends android.renderscript.ScriptIntrinsic { - method public void BNNM(android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation, int, int); - method public void CGBMV(int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int); - method public void CGEMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation); - method public void CGEMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int); - method public void CGERC(android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void CGERU(android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void CHBMV(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int); - method public void CHEMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation); - method public void CHEMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int); - method public void CHER(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void CHER2(int, android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void CHER2K(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation); - method public void CHERK(int, int, float, android.renderscript.Allocation, float, android.renderscript.Allocation); - method public void CHPMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int); - method public void CHPR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void CHPR2(int, android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void CSYMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation); - method public void CSYR2K(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation); - method public void CSYRK(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation); - method public void CTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void CTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void CTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void CTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void CTRMM(int, int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation); - method public void CTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void CTRSM(int, int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation); - method public void CTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void DGBMV(int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int); - method public void DGEMM(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation); - method public void DGEMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int); - method public void DGER(double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void DSBMV(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int); - method public void DSPMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int); - method public void DSPR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void DSPR2(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void DSYMM(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation); - method public void DSYMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int); - method public void DSYR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void DSYR2(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void DSYR2K(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation); - method public void DSYRK(int, int, double, android.renderscript.Allocation, double, android.renderscript.Allocation); - method public void DTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void DTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void DTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void DTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void DTRMM(int, int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation); - method public void DTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void DTRSM(int, int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation); - method public void DTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void SGBMV(int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int); - method public void SGEMM(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation); - method public void SGEMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int); - method public void SGER(float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void SSBMV(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int); - method public void SSPMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int); - method public void SSPR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void SSPR2(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void SSYMM(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation); - method public void SSYMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int); - method public void SSYR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void SSYR2(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void SSYR2K(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation); - method public void SSYRK(int, int, float, android.renderscript.Allocation, float, android.renderscript.Allocation); - method public void STBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void STBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void STPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void STPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void STRMM(int, int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation); - method public void STRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void STRSM(int, int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation); - method public void STRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void ZGBMV(int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int); - method public void ZGEMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation); - method public void ZGEMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int); - method public void ZGERC(android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void ZGERU(android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void ZHBMV(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int); - method public void ZHEMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation); - method public void ZHEMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int); - method public void ZHER(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void ZHER2(int, android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void ZHER2K(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation); - method public void ZHERK(int, int, double, android.renderscript.Allocation, double, android.renderscript.Allocation); - method public void ZHPMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int); - method public void ZHPR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void ZHPR2(int, android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); - method public void ZSYMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation); - method public void ZSYR2K(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation); - method public void ZSYRK(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation); - method public void ZTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void ZTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void ZTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void ZTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void ZTRMM(int, int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation); - method public void ZTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public void ZTRSM(int, int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation); - method public void ZTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); - method public static android.renderscript.ScriptIntrinsicBLAS create(android.renderscript.RenderScript); - field public static final int CONJ_TRANSPOSE = 113; // 0x71 - field public static final int LEFT = 141; // 0x8d - field public static final int LOWER = 122; // 0x7a - field public static final int NON_UNIT = 131; // 0x83 - field public static final int NO_TRANSPOSE = 111; // 0x6f - field public static final int RIGHT = 142; // 0x8e - field public static final int TRANSPOSE = 112; // 0x70 - field public static final int UNIT = 132; // 0x84 - field public static final int UPPER = 121; // 0x79 - } - - public class ScriptIntrinsicBlend extends android.renderscript.ScriptIntrinsic { - method public static android.renderscript.ScriptIntrinsicBlend create(android.renderscript.RenderScript, android.renderscript.Element); - method public void forEachAdd(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachAdd(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachClear(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachClear(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachDst(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachDst(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachDstAtop(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachDstAtop(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachDstIn(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachDstIn(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachDstOut(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachDstOut(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachDstOver(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachDstOver(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachMultiply(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachMultiply(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachSrc(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachSrc(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachSrcAtop(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachSrcAtop(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachSrcIn(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachSrcIn(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachSrcOut(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachSrcOut(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachSrcOver(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachSrcOver(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachSubtract(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachSubtract(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEachXor(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEachXor(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public android.renderscript.Script.KernelID getKernelIDAdd(); - method public android.renderscript.Script.KernelID getKernelIDClear(); - method public android.renderscript.Script.KernelID getKernelIDDst(); - method public android.renderscript.Script.KernelID getKernelIDDstAtop(); - method public android.renderscript.Script.KernelID getKernelIDDstIn(); - method public android.renderscript.Script.KernelID getKernelIDDstOut(); - method public android.renderscript.Script.KernelID getKernelIDDstOver(); - method public android.renderscript.Script.KernelID getKernelIDMultiply(); - method public android.renderscript.Script.KernelID getKernelIDSrc(); - method public android.renderscript.Script.KernelID getKernelIDSrcAtop(); - method public android.renderscript.Script.KernelID getKernelIDSrcIn(); - method public android.renderscript.Script.KernelID getKernelIDSrcOut(); - method public android.renderscript.Script.KernelID getKernelIDSrcOver(); - method public android.renderscript.Script.KernelID getKernelIDSubtract(); - method public android.renderscript.Script.KernelID getKernelIDXor(); - } - - public final class ScriptIntrinsicBlur extends android.renderscript.ScriptIntrinsic { - method public static android.renderscript.ScriptIntrinsicBlur create(android.renderscript.RenderScript, android.renderscript.Element); - method public void forEach(android.renderscript.Allocation); - method public void forEach(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public android.renderscript.Script.FieldID getFieldID_Input(); - method public android.renderscript.Script.KernelID getKernelID(); - method public void setInput(android.renderscript.Allocation); - method public void setRadius(float); - } - - public final class ScriptIntrinsicColorMatrix extends android.renderscript.ScriptIntrinsic { + @Deprecated public static final class ScriptGroup.Builder2 { + ctor @Deprecated public ScriptGroup.Builder2(android.renderscript.RenderScript); + method @Deprecated public android.renderscript.ScriptGroup.Input addInput(); + method @Deprecated public android.renderscript.ScriptGroup.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object...); + method @Deprecated public android.renderscript.ScriptGroup.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object...); + method @Deprecated public android.renderscript.ScriptGroup create(String, android.renderscript.ScriptGroup.Future...); + } + + @Deprecated public static final class ScriptGroup.Closure extends android.renderscript.BaseObj { + method @Deprecated public android.renderscript.ScriptGroup.Future getGlobal(android.renderscript.Script.FieldID); + method @Deprecated public android.renderscript.ScriptGroup.Future getReturn(); + } + + @Deprecated public static final class ScriptGroup.Future { + } + + @Deprecated public static final class ScriptGroup.Input { + } + + @Deprecated public abstract class ScriptIntrinsic extends android.renderscript.Script { + } + + @Deprecated public final class ScriptIntrinsic3DLUT extends android.renderscript.ScriptIntrinsic { + method @Deprecated public static android.renderscript.ScriptIntrinsic3DLUT create(android.renderscript.RenderScript, android.renderscript.Element); + method @Deprecated public void forEach(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEach(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public android.renderscript.Script.KernelID getKernelID(); + method @Deprecated public void setLUT(android.renderscript.Allocation); + } + + @Deprecated public final class ScriptIntrinsicBLAS extends android.renderscript.ScriptIntrinsic { + method @Deprecated public void BNNM(android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation, int, int); + method @Deprecated public void CGBMV(int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int); + method @Deprecated public void CGEMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation); + method @Deprecated public void CGEMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int); + method @Deprecated public void CGERC(android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void CGERU(android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void CHBMV(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int); + method @Deprecated public void CHEMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation); + method @Deprecated public void CHEMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int); + method @Deprecated public void CHER(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void CHER2(int, android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void CHER2K(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation); + method @Deprecated public void CHERK(int, int, float, android.renderscript.Allocation, float, android.renderscript.Allocation); + method @Deprecated public void CHPMV(int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Float2, android.renderscript.Allocation, int); + method @Deprecated public void CHPR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void CHPR2(int, android.renderscript.Float2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void CSYMM(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation); + method @Deprecated public void CSYR2K(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation); + method @Deprecated public void CSYRK(int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Float2, android.renderscript.Allocation); + method @Deprecated public void CTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void CTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void CTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void CTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void CTRMM(int, int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void CTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void CTRSM(int, int, int, int, android.renderscript.Float2, android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void CTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void DGBMV(int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int); + method @Deprecated public void DGEMM(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation); + method @Deprecated public void DGEMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int); + method @Deprecated public void DGER(double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void DSBMV(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int); + method @Deprecated public void DSPMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int); + method @Deprecated public void DSPR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void DSPR2(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void DSYMM(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation); + method @Deprecated public void DSYMV(int, double, android.renderscript.Allocation, android.renderscript.Allocation, int, double, android.renderscript.Allocation, int); + method @Deprecated public void DSYR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void DSYR2(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void DSYR2K(int, int, double, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation); + method @Deprecated public void DSYRK(int, int, double, android.renderscript.Allocation, double, android.renderscript.Allocation); + method @Deprecated public void DTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void DTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void DTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void DTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void DTRMM(int, int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void DTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void DTRSM(int, int, int, int, double, android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void DTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void SGBMV(int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int); + method @Deprecated public void SGEMM(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation); + method @Deprecated public void SGEMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int); + method @Deprecated public void SGER(float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void SSBMV(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int); + method @Deprecated public void SSPMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int); + method @Deprecated public void SSPR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void SSPR2(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void SSYMM(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation); + method @Deprecated public void SSYMV(int, float, android.renderscript.Allocation, android.renderscript.Allocation, int, float, android.renderscript.Allocation, int); + method @Deprecated public void SSYR(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void SSYR2(int, float, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void SSYR2K(int, int, float, android.renderscript.Allocation, android.renderscript.Allocation, float, android.renderscript.Allocation); + method @Deprecated public void SSYRK(int, int, float, android.renderscript.Allocation, float, android.renderscript.Allocation); + method @Deprecated public void STBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void STBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void STPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void STPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void STRMM(int, int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void STRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void STRSM(int, int, int, int, float, android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void STRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void ZGBMV(int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int); + method @Deprecated public void ZGEMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation); + method @Deprecated public void ZGEMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int); + method @Deprecated public void ZGERC(android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void ZGERU(android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void ZHBMV(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int); + method @Deprecated public void ZHEMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation); + method @Deprecated public void ZHEMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int); + method @Deprecated public void ZHER(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void ZHER2(int, android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void ZHER2K(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, double, android.renderscript.Allocation); + method @Deprecated public void ZHERK(int, int, double, android.renderscript.Allocation, double, android.renderscript.Allocation); + method @Deprecated public void ZHPMV(int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, int, android.renderscript.Double2, android.renderscript.Allocation, int); + method @Deprecated public void ZHPR(int, double, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void ZHPR2(int, android.renderscript.Double2, android.renderscript.Allocation, int, android.renderscript.Allocation, int, android.renderscript.Allocation); + method @Deprecated public void ZSYMM(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation); + method @Deprecated public void ZSYR2K(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation); + method @Deprecated public void ZSYRK(int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Double2, android.renderscript.Allocation); + method @Deprecated public void ZTBMV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void ZTBSV(int, int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void ZTPMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void ZTPSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void ZTRMM(int, int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void ZTRMV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public void ZTRSM(int, int, int, int, android.renderscript.Double2, android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void ZTRSV(int, int, int, android.renderscript.Allocation, android.renderscript.Allocation, int); + method @Deprecated public static android.renderscript.ScriptIntrinsicBLAS create(android.renderscript.RenderScript); + field @Deprecated public static final int CONJ_TRANSPOSE = 113; // 0x71 + field @Deprecated public static final int LEFT = 141; // 0x8d + field @Deprecated public static final int LOWER = 122; // 0x7a + field @Deprecated public static final int NON_UNIT = 131; // 0x83 + field @Deprecated public static final int NO_TRANSPOSE = 111; // 0x6f + field @Deprecated public static final int RIGHT = 142; // 0x8e + field @Deprecated public static final int TRANSPOSE = 112; // 0x70 + field @Deprecated public static final int UNIT = 132; // 0x84 + field @Deprecated public static final int UPPER = 121; // 0x79 + } + + @Deprecated public class ScriptIntrinsicBlend extends android.renderscript.ScriptIntrinsic { + method @Deprecated public static android.renderscript.ScriptIntrinsicBlend create(android.renderscript.RenderScript, android.renderscript.Element); + method @Deprecated public void forEachAdd(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachAdd(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachClear(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachClear(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachDst(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachDst(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachDstAtop(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachDstAtop(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachDstIn(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachDstIn(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachDstOut(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachDstOut(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachDstOver(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachDstOver(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachMultiply(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachMultiply(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachSrc(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachSrc(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachSrcAtop(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachSrcAtop(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachSrcIn(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachSrcIn(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachSrcOut(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachSrcOut(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachSrcOver(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachSrcOver(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachSubtract(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachSubtract(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEachXor(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEachXor(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDAdd(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDClear(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDDst(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDDstAtop(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDDstIn(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDDstOut(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDDstOver(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDMultiply(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDSrc(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDSrcAtop(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDSrcIn(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDSrcOut(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDSrcOver(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDSubtract(); + method @Deprecated public android.renderscript.Script.KernelID getKernelIDXor(); + } + + @Deprecated public final class ScriptIntrinsicBlur extends android.renderscript.ScriptIntrinsic { + method @Deprecated public static android.renderscript.ScriptIntrinsicBlur create(android.renderscript.RenderScript, android.renderscript.Element); + method @Deprecated public void forEach(android.renderscript.Allocation); + method @Deprecated public void forEach(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public android.renderscript.Script.FieldID getFieldID_Input(); + method @Deprecated public android.renderscript.Script.KernelID getKernelID(); + method @Deprecated public void setInput(android.renderscript.Allocation); + method @Deprecated public void setRadius(float); + } + + @Deprecated public final class ScriptIntrinsicColorMatrix extends android.renderscript.ScriptIntrinsic { method @Deprecated public static android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript, android.renderscript.Element); - method public static android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript); - method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public android.renderscript.Script.KernelID getKernelID(); - method public void setAdd(android.renderscript.Float4); - method public void setAdd(float, float, float, float); - method public void setColorMatrix(android.renderscript.Matrix4f); - method public void setColorMatrix(android.renderscript.Matrix3f); - method public void setGreyscale(); - method public void setRGBtoYUV(); - method public void setYUVtoRGB(); - } - - public final class ScriptIntrinsicConvolve3x3 extends android.renderscript.ScriptIntrinsic { - method public static android.renderscript.ScriptIntrinsicConvolve3x3 create(android.renderscript.RenderScript, android.renderscript.Element); - method public void forEach(android.renderscript.Allocation); - method public void forEach(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public android.renderscript.Script.FieldID getFieldID_Input(); - method public android.renderscript.Script.KernelID getKernelID(); - method public void setCoefficients(float[]); - method public void setInput(android.renderscript.Allocation); - } - - public final class ScriptIntrinsicConvolve5x5 extends android.renderscript.ScriptIntrinsic { - method public static android.renderscript.ScriptIntrinsicConvolve5x5 create(android.renderscript.RenderScript, android.renderscript.Element); - method public void forEach(android.renderscript.Allocation); - method public void forEach(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public android.renderscript.Script.FieldID getFieldID_Input(); - method public android.renderscript.Script.KernelID getKernelID(); - method public void setCoefficients(float[]); - method public void setInput(android.renderscript.Allocation); - } - - public final class ScriptIntrinsicHistogram extends android.renderscript.ScriptIntrinsic { - method public static android.renderscript.ScriptIntrinsicHistogram create(android.renderscript.RenderScript, android.renderscript.Element); - method public void forEach(android.renderscript.Allocation); - method public void forEach(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public void forEach_Dot(android.renderscript.Allocation); - method public void forEach_Dot(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public android.renderscript.Script.FieldID getFieldID_Input(); - method public android.renderscript.Script.KernelID getKernelID_Separate(); - method public void setDotCoefficients(float, float, float, float); - method public void setOutput(android.renderscript.Allocation); - } - - public final class ScriptIntrinsicLUT extends android.renderscript.ScriptIntrinsic { - method public static android.renderscript.ScriptIntrinsicLUT create(android.renderscript.RenderScript, android.renderscript.Element); - method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation); - method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public android.renderscript.Script.KernelID getKernelID(); - method public void setAlpha(int, int); - method public void setBlue(int, int); - method public void setGreen(int, int); - method public void setRed(int, int); - } - - public final class ScriptIntrinsicResize extends android.renderscript.ScriptIntrinsic { - method public static android.renderscript.ScriptIntrinsicResize create(android.renderscript.RenderScript); - method public void forEach_bicubic(android.renderscript.Allocation); - method public void forEach_bicubic(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); - method public android.renderscript.Script.FieldID getFieldID_Input(); - method public android.renderscript.Script.KernelID getKernelID_bicubic(); - method public void setInput(android.renderscript.Allocation); - } - - public final class ScriptIntrinsicYuvToRGB extends android.renderscript.ScriptIntrinsic { - method public static android.renderscript.ScriptIntrinsicYuvToRGB create(android.renderscript.RenderScript, android.renderscript.Element); - method public void forEach(android.renderscript.Allocation); - method public android.renderscript.Script.FieldID getFieldID_Input(); - method public android.renderscript.Script.KernelID getKernelID(); - method public void setInput(android.renderscript.Allocation); - } - - public class Short2 { - ctor public Short2(); - ctor public Short2(short, short); - field public short x; - field public short y; - } - - public class Short3 { - ctor public Short3(); - ctor public Short3(short, short, short); - field public short x; - field public short y; - field public short z; - } - - public class Short4 { - ctor public Short4(); - ctor public Short4(short, short, short, short); - field public short w; - field public short x; - field public short y; - field public short z; - } - - public class Type extends android.renderscript.BaseObj { - method public static android.renderscript.Type createX(android.renderscript.RenderScript, android.renderscript.Element, int); - method public static android.renderscript.Type createXY(android.renderscript.RenderScript, android.renderscript.Element, int, int); - method public static android.renderscript.Type createXYZ(android.renderscript.RenderScript, android.renderscript.Element, int, int, int); - method public int getCount(); - method public android.renderscript.Element getElement(); - method public int getX(); - method public int getY(); - method public int getYuv(); - method public int getZ(); - method public boolean hasFaces(); - method public boolean hasMipmaps(); - } - - public static class Type.Builder { - ctor public Type.Builder(android.renderscript.RenderScript, android.renderscript.Element); - method public android.renderscript.Type create(); - method public android.renderscript.Type.Builder setFaces(boolean); - method public android.renderscript.Type.Builder setMipmaps(boolean); - method public android.renderscript.Type.Builder setX(int); - method public android.renderscript.Type.Builder setY(int); - method public android.renderscript.Type.Builder setYuvFormat(int); - method public android.renderscript.Type.Builder setZ(int); - } - - public enum Type.CubemapFace { - enum_constant public static final android.renderscript.Type.CubemapFace NEGATIVE_X; - enum_constant public static final android.renderscript.Type.CubemapFace NEGATIVE_Y; - enum_constant public static final android.renderscript.Type.CubemapFace NEGATIVE_Z; - enum_constant public static final android.renderscript.Type.CubemapFace POSITIVE_X; - enum_constant public static final android.renderscript.Type.CubemapFace POSITIVE_Y; - enum_constant public static final android.renderscript.Type.CubemapFace POSITIVE_Z; + method @Deprecated public static android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript); + method @Deprecated public void forEach(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEach(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public android.renderscript.Script.KernelID getKernelID(); + method @Deprecated public void setAdd(android.renderscript.Float4); + method @Deprecated public void setAdd(float, float, float, float); + method @Deprecated public void setColorMatrix(android.renderscript.Matrix4f); + method @Deprecated public void setColorMatrix(android.renderscript.Matrix3f); + method @Deprecated public void setGreyscale(); + method @Deprecated public void setRGBtoYUV(); + method @Deprecated public void setYUVtoRGB(); + } + + @Deprecated public final class ScriptIntrinsicConvolve3x3 extends android.renderscript.ScriptIntrinsic { + method @Deprecated public static android.renderscript.ScriptIntrinsicConvolve3x3 create(android.renderscript.RenderScript, android.renderscript.Element); + method @Deprecated public void forEach(android.renderscript.Allocation); + method @Deprecated public void forEach(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public android.renderscript.Script.FieldID getFieldID_Input(); + method @Deprecated public android.renderscript.Script.KernelID getKernelID(); + method @Deprecated public void setCoefficients(float[]); + method @Deprecated public void setInput(android.renderscript.Allocation); + } + + @Deprecated public final class ScriptIntrinsicConvolve5x5 extends android.renderscript.ScriptIntrinsic { + method @Deprecated public static android.renderscript.ScriptIntrinsicConvolve5x5 create(android.renderscript.RenderScript, android.renderscript.Element); + method @Deprecated public void forEach(android.renderscript.Allocation); + method @Deprecated public void forEach(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public android.renderscript.Script.FieldID getFieldID_Input(); + method @Deprecated public android.renderscript.Script.KernelID getKernelID(); + method @Deprecated public void setCoefficients(float[]); + method @Deprecated public void setInput(android.renderscript.Allocation); + } + + @Deprecated public final class ScriptIntrinsicHistogram extends android.renderscript.ScriptIntrinsic { + method @Deprecated public static android.renderscript.ScriptIntrinsicHistogram create(android.renderscript.RenderScript, android.renderscript.Element); + method @Deprecated public void forEach(android.renderscript.Allocation); + method @Deprecated public void forEach(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public void forEach_Dot(android.renderscript.Allocation); + method @Deprecated public void forEach_Dot(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public android.renderscript.Script.FieldID getFieldID_Input(); + method @Deprecated public android.renderscript.Script.KernelID getKernelID_Separate(); + method @Deprecated public void setDotCoefficients(float, float, float, float); + method @Deprecated public void setOutput(android.renderscript.Allocation); + } + + @Deprecated public final class ScriptIntrinsicLUT extends android.renderscript.ScriptIntrinsic { + method @Deprecated public static android.renderscript.ScriptIntrinsicLUT create(android.renderscript.RenderScript, android.renderscript.Element); + method @Deprecated public void forEach(android.renderscript.Allocation, android.renderscript.Allocation); + method @Deprecated public void forEach(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public android.renderscript.Script.KernelID getKernelID(); + method @Deprecated public void setAlpha(int, int); + method @Deprecated public void setBlue(int, int); + method @Deprecated public void setGreen(int, int); + method @Deprecated public void setRed(int, int); + } + + @Deprecated public final class ScriptIntrinsicResize extends android.renderscript.ScriptIntrinsic { + method @Deprecated public static android.renderscript.ScriptIntrinsicResize create(android.renderscript.RenderScript); + method @Deprecated public void forEach_bicubic(android.renderscript.Allocation); + method @Deprecated public void forEach_bicubic(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions); + method @Deprecated public android.renderscript.Script.FieldID getFieldID_Input(); + method @Deprecated public android.renderscript.Script.KernelID getKernelID_bicubic(); + method @Deprecated public void setInput(android.renderscript.Allocation); + } + + @Deprecated public final class ScriptIntrinsicYuvToRGB extends android.renderscript.ScriptIntrinsic { + method @Deprecated public static android.renderscript.ScriptIntrinsicYuvToRGB create(android.renderscript.RenderScript, android.renderscript.Element); + method @Deprecated public void forEach(android.renderscript.Allocation); + method @Deprecated public android.renderscript.Script.FieldID getFieldID_Input(); + method @Deprecated public android.renderscript.Script.KernelID getKernelID(); + method @Deprecated public void setInput(android.renderscript.Allocation); + } + + @Deprecated public class Short2 { + ctor @Deprecated public Short2(); + ctor @Deprecated public Short2(short, short); + field @Deprecated public short x; + field @Deprecated public short y; + } + + @Deprecated public class Short3 { + ctor @Deprecated public Short3(); + ctor @Deprecated public Short3(short, short, short); + field @Deprecated public short x; + field @Deprecated public short y; + field @Deprecated public short z; + } + + @Deprecated public class Short4 { + ctor @Deprecated public Short4(); + ctor @Deprecated public Short4(short, short, short, short); + field @Deprecated public short w; + field @Deprecated public short x; + field @Deprecated public short y; + field @Deprecated public short z; + } + + @Deprecated public class Type extends android.renderscript.BaseObj { + method @Deprecated public static android.renderscript.Type createX(android.renderscript.RenderScript, android.renderscript.Element, int); + method @Deprecated public static android.renderscript.Type createXY(android.renderscript.RenderScript, android.renderscript.Element, int, int); + method @Deprecated public static android.renderscript.Type createXYZ(android.renderscript.RenderScript, android.renderscript.Element, int, int, int); + method @Deprecated public int getCount(); + method @Deprecated public android.renderscript.Element getElement(); + method @Deprecated public int getX(); + method @Deprecated public int getY(); + method @Deprecated public int getYuv(); + method @Deprecated public int getZ(); + method @Deprecated public boolean hasFaces(); + method @Deprecated public boolean hasMipmaps(); + } + + @Deprecated public static class Type.Builder { + ctor @Deprecated public Type.Builder(android.renderscript.RenderScript, android.renderscript.Element); + method @Deprecated public android.renderscript.Type create(); + method @Deprecated public android.renderscript.Type.Builder setFaces(boolean); + method @Deprecated public android.renderscript.Type.Builder setMipmaps(boolean); + method @Deprecated public android.renderscript.Type.Builder setX(int); + method @Deprecated public android.renderscript.Type.Builder setY(int); + method @Deprecated public android.renderscript.Type.Builder setYuvFormat(int); + method @Deprecated public android.renderscript.Type.Builder setZ(int); + } + + @Deprecated public enum Type.CubemapFace { + enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace NEGATIVE_X; + enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace NEGATIVE_Y; + enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace NEGATIVE_Z; + enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace POSITIVE_X; + enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace POSITIVE_Y; + enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace POSITIVE_Z; enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace POSITVE_X; enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace POSITVE_Y; enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace POSITVE_Z; @@ -39604,22 +39599,22 @@ package android.telecom { method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection); method public final void connectionServiceFocusReleased(); method @Nullable public final android.telecom.RemoteConference createRemoteIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest); - method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method @Nullable public final android.telecom.RemoteConnection createRemoteIncomingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest); method @Nullable public final android.telecom.RemoteConference createRemoteOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest); - method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method @Nullable public final android.telecom.RemoteConnection createRemoteOutgoingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest); method public final java.util.Collection<android.telecom.Conference> getAllConferences(); method public final java.util.Collection<android.telecom.Connection> getAllConnections(); method public final android.os.IBinder onBind(android.content.Intent); method public void onConference(android.telecom.Connection, android.telecom.Connection); method public void onConnectionServiceFocusGained(); method public void onConnectionServiceFocusLost(); - method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest); + method @Nullable public android.telecom.Conference onCreateIncomingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest); method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); - method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest); - method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest); + method @Nullable public android.telecom.Conference onCreateOutgoingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest); + method public void onCreateOutgoingConferenceFailed(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); @@ -40536,6 +40531,9 @@ package android.telephony { field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool"; field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool"; field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool"; + field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL = "supports_device_to_device_communication_using_dtmf_bool"; + field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL = "supports_device_to_device_communication_using_rtp_bool"; + field public static final String KEY_SUPPORTS_SDP_NEGOTIATION_OF_D2D_RTP_HEADER_EXTENSIONS_BOOL = "supports_sdp_negotiation_of_d2d_rtp_header_extensions_bool"; field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool"; field public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL = "support_add_conference_participants_bool"; field public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = "support_adhoc_conference_calls_bool"; @@ -40614,14 +40612,6 @@ package android.telephony { public static final class CarrierConfigManager.Iwlan { field public static final int AUTHENTICATION_METHOD_CERT = 1; // 0x1 field public static final int AUTHENTICATION_METHOD_EAP_ONLY = 0; // 0x0 - field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2 - field public static final int DH_GROUP_1536_BIT_MODP = 5; // 0x5 - field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe - field public static final int DH_GROUP_3072_BIT_MODP = 15; // 0xf - field public static final int DH_GROUP_4096_BIT_MODP = 16; // 0x10 - field public static final int DH_GROUP_NONE = 0; // 0x0 - field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc - field public static final int ENCRYPTION_ALGORITHM_AES_CTR = 13; // 0xd field public static final int EPDG_ADDRESS_CELLULAR_LOC = 3; // 0x3 field public static final int EPDG_ADDRESS_PCO = 2; // 0x2 field public static final int EPDG_ADDRESS_PLMN = 1; // 0x1 @@ -40629,12 +40619,6 @@ package android.telephony { field public static final int ID_TYPE_FQDN = 2; // 0x2 field public static final int ID_TYPE_KEY_ID = 11; // 0xb field public static final int ID_TYPE_RFC822_ADDR = 3; // 0x3 - field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5 - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2 - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd - field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe - field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0 field public static final String KEY_ADD_KE_TO_CHILD_SESSION_REKEY_BOOL = "iwlan.add_ke_to_child_session_rekey_bool"; field public static final String KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT = "iwlan.child_sa_rekey_hard_timer_sec_int"; field public static final String KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT = "iwlan.child_sa_rekey_soft_timer_sec_int"; @@ -40654,10 +40638,6 @@ package android.telephony { field public static final String KEY_IKE_REMOTE_ID_TYPE_INT = "iwlan.ike_remote_id_type_int"; field public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_encryption_aes_cbc_key_size_int_array"; field public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_encryption_aes_ctr_key_size_int_array"; - field public static final int KEY_LEN_AES_128 = 128; // 0x80 - field public static final int KEY_LEN_AES_192 = 192; // 0xc0 - field public static final int KEY_LEN_AES_256 = 256; // 0x100 - field public static final int KEY_LEN_UNUSED = 0; // 0x0 field public static final String KEY_MAX_RETRIES_INT = "iwlan.max_retries_int"; field public static final String KEY_MCC_MNCS_STRING_ARRAY = "iwlan.mcc_mncs_string_array"; field public static final String KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT = "iwlan.natt_keep_alive_timer_sec_int"; @@ -40667,11 +40647,6 @@ package android.telephony { field public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = "iwlan.supported_ike_session_encryption_algorithms_int_array"; field public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY = "iwlan.supported_integrity_algorithms_int_array"; field public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY = "iwlan.supported_prf_algorithms_int_array"; - field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4 - field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2 - field public static final int PSEUDORANDOM_FUNCTION_SHA2_256 = 5; // 0x5 - field public static final int PSEUDORANDOM_FUNCTION_SHA2_384 = 6; // 0x6 - field public static final int PSEUDORANDOM_FUNCTION_SHA2_512 = 7; // 0x7 } public abstract class CellIdentity implements android.os.Parcelable { @@ -42142,7 +42117,7 @@ package android.telephony { } public static interface TelephonyCallback.CallStateListener { - method @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public void onCallStateChanged(int, @Nullable String); + method public void onCallStateChanged(int); } public static interface TelephonyCallback.CarrierNetworkListener { @@ -42912,7 +42887,7 @@ package android.telephony.ims { method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getVoWiFiModeSetting(); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isAdvancedCallingSettingEnabled(); - method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isCrossSimCallingEnabledByUser() throws android.telephony.ims.ImsException; + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isCrossSimCallingEnabled() throws android.telephony.ims.ImsException; method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isTtyOverVolteEnabled(); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiRoamingSettingEnabled(); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiSettingEnabled(); @@ -46569,9 +46544,9 @@ package android.view { public class GestureDetector { ctor @Deprecated public GestureDetector(android.view.GestureDetector.OnGestureListener, android.os.Handler); ctor @Deprecated public GestureDetector(android.view.GestureDetector.OnGestureListener); - ctor public GestureDetector(android.content.Context, android.view.GestureDetector.OnGestureListener); - ctor public GestureDetector(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler); - ctor public GestureDetector(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler, boolean); + ctor public GestureDetector(@UiContext android.content.Context, android.view.GestureDetector.OnGestureListener); + ctor public GestureDetector(@UiContext android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler); + ctor public GestureDetector(@UiContext android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler, boolean); method public boolean isLongpressEnabled(); method public boolean onGenericMotionEvent(android.view.MotionEvent); method public boolean onTouchEvent(android.view.MotionEvent); @@ -47260,7 +47235,7 @@ package android.view { method public abstract android.view.LayoutInflater cloneInContext(android.content.Context); method public final android.view.View createView(String, String, android.util.AttributeSet) throws java.lang.ClassNotFoundException, android.view.InflateException; method @Nullable public final android.view.View createView(@NonNull android.content.Context, @NonNull String, @Nullable String, @Nullable android.util.AttributeSet) throws java.lang.ClassNotFoundException, android.view.InflateException; - method public static android.view.LayoutInflater from(android.content.Context); + method public static android.view.LayoutInflater from(@UiContext android.content.Context); method public android.content.Context getContext(); method public final android.view.LayoutInflater.Factory getFactory(); method public final android.view.LayoutInflater.Factory2 getFactory2(); @@ -48154,7 +48129,7 @@ package android.view { method public final boolean getClipToOutline(); method @Nullable public final android.view.contentcapture.ContentCaptureSession getContentCaptureSession(); method public CharSequence getContentDescription(); - method public final android.content.Context getContext(); + method @UiContext public final android.content.Context getContext(); method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo(); method public final boolean getDefaultFocusHighlightEnabled(); method public static int getDefaultSize(int, int); @@ -48953,7 +48928,7 @@ package android.view { public class ViewConfiguration { ctor @Deprecated public ViewConfiguration(); - method public static android.view.ViewConfiguration get(android.content.Context); + method public static android.view.ViewConfiguration get(@UiContext android.content.Context); method @Deprecated @FloatRange(from=1.0) public static float getAmbiguousGestureMultiplier(); method public static long getDefaultActionModeHideDuration(); method public static int getDoubleTapTimeout(); @@ -49511,7 +49486,7 @@ package android.view { } public abstract class Window { - ctor public Window(android.content.Context); + ctor public Window(@UiContext android.content.Context); method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams); method public void addFlags(int); method public final void addOnFrameMetricsAvailableListener(@NonNull android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler); @@ -49526,7 +49501,7 @@ package android.view { method public int getColorMode(); method public final android.view.Window getContainer(); method public android.transition.Scene getContentScene(); - method public final android.content.Context getContext(); + method @UiContext public final android.content.Context getContext(); method @Nullable public abstract android.view.View getCurrentFocus(); method @NonNull public abstract android.view.View getDecorView(); method public static int getDefaultFeatures(android.content.Context); @@ -51476,6 +51451,7 @@ package android.view.inputmethod { method public int describeContents(); method public void dump(android.util.Printer, String); method public android.content.ComponentName getComponent(); + method public int getConfigChanges(); method public String getId(); method public int getIsDefaultResourceId(); method public String getPackageName(); @@ -54982,6 +54958,7 @@ package android.widget { ctor public RemoteViews(@NonNull java.util.Map<android.util.SizeF,android.widget.RemoteViews>); ctor public RemoteViews(android.widget.RemoteViews); ctor public RemoteViews(android.os.Parcel); + method public void addStableView(@IdRes int, @NonNull android.widget.RemoteViews, int); method public void addView(@IdRes int, android.widget.RemoteViews); method public android.view.View apply(android.content.Context, android.view.ViewGroup); method @Deprecated public android.widget.RemoteViews clone(); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index c7d40585dd00..18b0a4344414 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -59,6 +59,10 @@ package android.content { method @NonNull public android.os.UserHandle getUser(); } + public class Intent implements java.lang.Cloneable android.os.Parcelable { + field public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE"; + } + } package android.content.pm { @@ -213,6 +217,13 @@ package android.net { field @NonNull public final java.util.List<java.lang.String> underlyingIfaces; } + public class VpnManager { + field @Deprecated public static final int TYPE_VPN_LEGACY = 3; // 0x3 + field public static final int TYPE_VPN_NONE = -1; // 0xffffffff + field public static final int TYPE_VPN_PLATFORM = 2; // 0x2 + field public static final int TYPE_VPN_SERVICE = 1; // 0x1 + } + } package android.os { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 5ca4d35d4c22..6019ab56dea7 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -147,6 +147,7 @@ package android { field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY"; field public static final String MANAGE_SMARTSPACE = "android.permission.MANAGE_SMARTSPACE"; field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER"; + field public static final String MANAGE_SPEECH_RECOGNITION = "android.permission.MANAGE_SPEECH_RECOGNITION"; field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS"; field public static final String MANAGE_TEST_NETWORKS = "android.permission.MANAGE_TEST_NETWORKS"; field public static final String MANAGE_TIME_AND_ZONE_DETECTION = "android.permission.MANAGE_TIME_AND_ZONE_DETECTION"; @@ -359,6 +360,7 @@ package android { field public static final int config_systemGallery = 17039399; // 0x1040027 field public static final int config_systemShell = 17039402; // 0x104002a field public static final int config_systemSpeechRecognizer = 17039406; // 0x104002e + field public static final int config_systemTelevisionNotificationHandler = 17039409; // 0x1040031 field public static final int config_systemWellbeing = 17039408; // 0x1040030 field public static final int config_systemWifiCoexManager = 17039407; // 0x104002f } @@ -380,7 +382,7 @@ package android.accounts { package android.app { - public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback { + @UiContext public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback { method public void convertFromTranslucent(); method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions); method @Deprecated public boolean isBackgroundVisibleBehind(); @@ -2172,6 +2174,7 @@ package android.content { field public static final String OEM_LOCK_SERVICE = "oem_lock"; field public static final String PERMISSION_SERVICE = "permission"; field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block"; + field public static final String POWER_EXEMPTION_SERVICE = "power_exemption"; field public static final String REBOOT_READINESS_SERVICE = "reboot_readiness"; field public static final String ROLLBACK_SERVICE = "rollback"; field public static final String SEARCH_UI_SERVICE = "search_ui"; @@ -2881,11 +2884,16 @@ package android.graphics.fonts { } public static final class FontFamilyUpdateRequest.FontFamily { - ctor public FontFamilyUpdateRequest.FontFamily(@NonNull String, @NonNull java.util.List<android.graphics.fonts.FontFamilyUpdateRequest.Font>); method @NonNull public java.util.List<android.graphics.fonts.FontFamilyUpdateRequest.Font> getFonts(); method @NonNull public String getName(); } + public static final class FontFamilyUpdateRequest.FontFamily.Builder { + ctor public FontFamilyUpdateRequest.FontFamily.Builder(@NonNull String, @NonNull java.util.List<android.graphics.fonts.FontFamilyUpdateRequest.Font>); + method @NonNull public android.graphics.fonts.FontFamilyUpdateRequest.FontFamily.Builder addFont(@NonNull android.graphics.fonts.FontFamilyUpdateRequest.Font); + method @NonNull public android.graphics.fonts.FontFamilyUpdateRequest.FontFamily build(); + } + public final class FontFileUpdateRequest { ctor public FontFileUpdateRequest(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[]); method @NonNull public android.os.ParcelFileDescriptor getParcelFileDescriptor(); @@ -2893,7 +2901,7 @@ package android.graphics.fonts { } public class FontManager { - method @NonNull public android.text.FontConfig getFontConfig(); + method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public android.text.FontConfig getFontConfig(); method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int); field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff @@ -3102,6 +3110,7 @@ package android.hardware.hdmi { method @NonNull public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevices(); method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getHdmiCecEnabled(); method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getHdmiCecVersion(); + method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getHdmiCecVolumeControlEnabled(); method public int getPhysicalAddress(); method @Nullable public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient(); method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public String getPowerControlMode(); @@ -3109,6 +3118,8 @@ package android.hardware.hdmi { method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient(); method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getSystemAudioModeMuting(); method @Nullable public android.hardware.hdmi.HdmiTvClient getTvClient(); + method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getTvSendStandbyOnSleep(); + method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getTvWakeOnOneTouchPlay(); method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public java.util.List<java.lang.String> getUserCecSettings(); method public boolean isDeviceConnected(@NonNull android.hardware.hdmi.HdmiDeviceInfo); method public void powerOffDevice(@NonNull android.hardware.hdmi.HdmiDeviceInfo); @@ -3117,10 +3128,13 @@ package android.hardware.hdmi { method public void setActiveSource(@NonNull android.hardware.hdmi.HdmiDeviceInfo); method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecEnabled(@NonNull int); method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecVersion(@NonNull int); + method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecVolumeControlEnabled(int); method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setPowerControlMode(@NonNull String); method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setPowerStateChangeOnActiveSourceLost(@NonNull String); method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean); method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSystemAudioModeMuting(@NonNull int); + method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setTvSendStandbyOnSleep(@NonNull int); + method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setTvWakeOnOneTouchPlay(@NonNull int); field public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE"; field public static final int AVR_VOLUME_MUTED = 101; // 0x65 field public static final String CEC_SETTING_NAME_HDMI_CEC_ENABLED = "hdmi_cec_enabled"; @@ -3128,6 +3142,9 @@ package android.hardware.hdmi { field public static final String CEC_SETTING_NAME_POWER_CONTROL_MODE = "send_standby_on_sleep"; field public static final String CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST = "power_state_change_on_active_source_lost"; field public static final String CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING = "system_audio_mode_muting"; + field public static final String CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP = "tv_send_standby_on_sleep"; + field public static final String CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY = "tv_wake_on_one_touch_play"; + field public static final String CEC_SETTING_NAME_VOLUME_CONTROL_MODE = "volume_control_enabled"; field public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 162; // 0xa2 field public static final int CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION = 160; // 0xa0 field public static final int CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE = 161; // 0xa1 @@ -3223,6 +3240,12 @@ package android.hardware.hdmi { field public static final int TIMER_STATUS_PROGRAMMED_INFO_MIGHT_NOT_ENOUGH_SPACE = 11; // 0xb field public static final int TIMER_STATUS_PROGRAMMED_INFO_NOT_ENOUGH_SPACE = 9; // 0x9 field public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 10; // 0xa + field public static final int TV_SEND_STANDBY_ON_SLEEP_DISABLED = 0; // 0x0 + field public static final int TV_SEND_STANDBY_ON_SLEEP_ENABLED = 1; // 0x1 + field public static final int TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED = 0; // 0x0 + field public static final int TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED = 1; // 0x1 + field public static final int VOLUME_CONTROL_DISABLED = 0; // 0x0 + field public static final int VOLUME_CONTROL_ENABLED = 1; // 0x1 } public static interface HdmiControlManager.CecSettingChangeListener { @@ -7462,22 +7485,22 @@ package android.net.netstats.provider { package android.net.sip { - public class SipAudioCall { - method @Nullable public android.net.rtp.AudioGroup getAudioGroup(); - method public void setAudioGroup(@NonNull android.net.rtp.AudioGroup); + @Deprecated public class SipAudioCall { + method @Deprecated @Nullable public android.net.rtp.AudioGroup getAudioGroup(); + method @Deprecated public void setAudioGroup(@NonNull android.net.rtp.AudioGroup); } - public class SipManager { - method @NonNull public java.util.List<android.net.sip.SipProfile> getProfiles() throws android.net.sip.SipException; - field public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED"; - field public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL"; - field public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE"; - field public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP"; - field public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP"; + @Deprecated public class SipManager { + method @Deprecated @NonNull public java.util.List<android.net.sip.SipProfile> getProfiles() throws android.net.sip.SipException; + field @Deprecated public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED"; + field @Deprecated public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL"; + field @Deprecated public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE"; + field @Deprecated public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP"; + field @Deprecated public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP"; } - public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable { - method public int getCallingUid(); + @Deprecated public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable { + method @Deprecated public int getCallingUid(); } } @@ -8152,6 +8175,25 @@ package android.os { field @NonNull public static final android.os.Parcelable.Creator<android.os.ParcelableHolder> CREATOR; } + public class PowerExemptionManager { + method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToPermanentAllowList(@NonNull String); + method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToPermanentAllowList(@NonNull java.util.List<java.lang.String>); + method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void addToTemporaryAllowList(@NonNull String, long, int, @Nullable String); + method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long addToTemporaryAllowListForEvent(@NonNull String, int, int, @Nullable String); + method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromAllowList(@NonNull String); + field public static final int EVENT_MMS = 2; // 0x2 + field public static final int EVENT_SMS = 1; // 0x1 + field public static final int EVENT_UNSPECIFIED = 0; // 0x0 + field public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67 + field public static final int REASON_GEOFENCING = 100; // 0x64 + field public static final int REASON_OTHER = 1; // 0x1 + field public static final int REASON_PUSH_MESSAGING = 101; // 0x65 + field public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102; // 0x66 + field public static final int REASON_UNKNOWN = 0; // 0x0 + field public static final int TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0 + field public static final int TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1 + } + public final class PowerManager { method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long); method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean forceSuspend(); @@ -9931,11 +9973,13 @@ package android.service.resumeonreboot { package android.service.rotationresolver { public final class RotationResolutionRequest implements android.os.Parcelable { + ctor public RotationResolutionRequest(@NonNull String, int, int, boolean, long); method public int describeContents(); method public int getCurrentRotation(); method @NonNull public String getPackageName(); method public int getProposedRotation(); method public long getTimeoutMillis(); + method public boolean shouldUseCamera(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.rotationresolver.RotationResolutionRequest> CREATOR; } @@ -10207,6 +10251,7 @@ package android.service.voice { ctor public HotwordDetectionService(); method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); method public void onDetectFromDspSource(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.DspHotwordDetectionCallback); + method public void onUpdateState(@Nullable android.os.Bundle, @Nullable android.os.SharedMemory); field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService"; } @@ -10217,10 +10262,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 public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, @Nullable android.os.Bundle, @Nullable android.os.SharedMemory, android.service.voice.AlwaysOnHotwordDetector.Callback); method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager(); - method public final int setHotwordDetectionConfig(@Nullable android.os.Bundle); - field public static final int HOTWORD_CONFIG_FAILURE = 1; // 0x1 - field public static final int HOTWORD_CONFIG_SUCCESS = 0; // 0x0 } } @@ -11403,7 +11446,7 @@ package android.telephony { field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27; // 0x1b field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26; // 0x1a field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; // 0x4 - field @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6 + field public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6 field public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; // 0x11 field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_LOCATION_CHANGED = 5; // 0x5 @@ -11415,6 +11458,7 @@ package android.telephony { field public static final int EVENT_DISPLAY_INFO_CHANGED = 21; // 0x15 field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25; // 0x19 field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28; // 0x1c + field @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_LEGACY_CALL_STATE_CHANGED = 36; // 0x24 field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3; // 0x3 field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_OEM_HOOK_RAW = 15; // 0xf field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29; // 0x1d @@ -11618,7 +11662,7 @@ package android.telephony { method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult setIccLockEnabled(boolean, @NonNull String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMobileDataPolicyEnabled(int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean); - method public int setNrDualConnectivityState(int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setNrDualConnectivityState(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean); @@ -12013,7 +12057,6 @@ package android.telephony.data { } public final class EpsBearerQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes { - method @NonNull public static android.telephony.data.EpsBearerQosSessionAttributes create(@NonNull android.os.Parcel); method public int describeContents(); method public long getGuaranteedDownlinkBitRate(); method public long getGuaranteedUplinkBitRate(); @@ -13796,6 +13839,7 @@ package android.util { package android.uwb { public final class AngleMeasurement implements android.os.Parcelable { + ctor public AngleMeasurement(double, double, double); method public int describeContents(); method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel(); method @FloatRange(from=0.0, to=3.141592653589793) public double getErrorRadians(); @@ -13804,14 +13848,6 @@ package android.uwb { field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleMeasurement> CREATOR; } - public static final class AngleMeasurement.Builder { - ctor public AngleMeasurement.Builder(); - method @NonNull public android.uwb.AngleMeasurement build(); - method @NonNull public android.uwb.AngleMeasurement.Builder setConfidenceLevel(double); - method @NonNull public android.uwb.AngleMeasurement.Builder setErrorRadians(double); - method @NonNull public android.uwb.AngleMeasurement.Builder setRadians(double); - } - public final class AngleOfArrivalMeasurement implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.uwb.AngleMeasurement getAltitude(); @@ -13821,10 +13857,9 @@ package android.uwb { } public static final class AngleOfArrivalMeasurement.Builder { - ctor public AngleOfArrivalMeasurement.Builder(); + ctor public AngleOfArrivalMeasurement.Builder(@NonNull android.uwb.AngleMeasurement); method @NonNull public android.uwb.AngleOfArrivalMeasurement build(); method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAltitude(@NonNull android.uwb.AngleMeasurement); - method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAzimuth(@NonNull android.uwb.AngleMeasurement); } public final class DistanceMeasurement implements android.os.Parcelable { @@ -13924,7 +13959,7 @@ package android.uwb { public final class UwbManager { method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public long elapsedRealtimeResolutionNanos(); method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.PersistableBundle getSpecificationInfo(); - method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public AutoCloseable openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback); + method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.CancellationSignal openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback); method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback); method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback); } diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 7b5b1989c1e5..1713e2d50b81 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -87,7 +87,7 @@ package android.animation { package android.app { - public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback { + @UiContext public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback { method public void onMovedToDisplay(int, android.content.res.Configuration); } @@ -414,6 +414,7 @@ package android.app.admin { method public long getLastNetworkLogRetrievalTime(); method public long getLastSecurityLogRetrievalTime(); method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle); + method @NonNull @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public java.util.Set<java.lang.String> getPolicyExemptApps(); method public boolean isCurrentInputMethodSetByOwner(); method public boolean isFactoryResetProtectionPolicySupported(); method @RequiresPermission(anyOf={"android.permission.MARK_DEVICE_ORGANIZATION_OWNED", "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName); @@ -706,6 +707,10 @@ package android.content { method public int getDisplayId(); } + public class SyncAdapterType implements android.os.Parcelable { + method @Nullable public String getPackageName(); + } + } package android.content.integrity { @@ -721,6 +726,8 @@ package android.content.pm { public class ActivityInfo extends android.content.pm.ComponentInfo implements android.os.Parcelable { method public static boolean isTranslucentOrFloating(android.content.res.TypedArray); + field public static final long FORCE_NON_RESIZE_APP = 181136395L; // 0xacbec0bL + field public static final long FORCE_RESIZE_APP = 174042936L; // 0xa5faf38L field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2 } @@ -938,6 +945,12 @@ package android.graphics { method public void splitVertically(@NonNull android.graphics.Rect...); } + public class Typeface { + method @NonNull public static java.util.Map<java.lang.String,android.graphics.Typeface> deserializeFontMap(@NonNull java.nio.ByteBuffer) throws java.io.IOException; + method @Nullable public static android.os.SharedMemory getSystemFontMapSharedMemory(); + method @NonNull public static android.os.SharedMemory serializeFontMap(@NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws android.system.ErrnoException, java.io.IOException; + } + } package android.graphics.drawable { @@ -960,7 +973,7 @@ package android.graphics.drawable { package android.graphics.fonts { public class FontManager { - method @NonNull public android.text.FontConfig getFontConfig(); + method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public android.text.FontConfig getFontConfig(); method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int); field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff @@ -1176,7 +1189,7 @@ package android.hardware.soundtrigger { package android.inputmethodservice { - public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService { + @UiContext public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService { field public static final long FINISH_INPUT_NO_FALLBACK_CONNECTION = 156215187L; // 0x94fa793L } @@ -1483,6 +1496,14 @@ package android.net { package android.os { + public final class BatteryStatsManager { + method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void resetBattery(boolean); + method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setBatteryLevel(int, boolean); + method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setChargerAcOnline(boolean, boolean); + method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void suspendBatteryInput(); + method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void unplugBattery(boolean); + } + public class Build { method public static boolean is64BitAbi(String); field public static final boolean IS_EMULATOR; @@ -2123,6 +2144,14 @@ package android.service.watchdog { } +package android.speech { + + public class SpeechRecognizer { + method public void setTemporaryOnDeviceRecognizer(@Nullable android.content.ComponentName); + } + +} + package android.telecom { public static class Call.Details { @@ -2148,6 +2177,10 @@ package android.telecom { method @NonNull public android.telecom.ConnectionRequest.Builder setVideoState(int); } + public abstract class ConnectionService extends android.app.Service { + method public void onBindClient(@Nullable android.content.Intent); + } + } package android.telephony { @@ -2325,7 +2358,6 @@ package android.util { field public static final String FFLAG_PREFIX = "sys.fflag."; field public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid"; field public static final String PERSIST_PREFIX = "persist.sys.fflag.override."; - field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press"; field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2"; } @@ -2525,6 +2557,7 @@ package android.view { method public default int getDisplayImePolicy(int); method public default void holdLock(android.os.IBinder, int); 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); @@ -2700,6 +2733,10 @@ package android.view.inputmethod { method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>); } + public final class InputMethodInfo implements android.os.Parcelable { + ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int); + } + public final class InputMethodManager { method public int getDisplayId(); method public boolean hasActiveInputConnection(@Nullable android.view.View); @@ -2898,7 +2935,7 @@ package android.window { method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo); method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo); method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer(); - method @BinderThread public void removeStartingWindow(int); + method @BinderThread public void removeStartingWindow(int, @Nullable android.view.SurfaceControl, @Nullable android.graphics.Rect, boolean); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean); method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer(); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 0b5958695dff..8977ba774d0b 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -5775,11 +5775,14 @@ public final class ActivityThread extends ClientTransactionHandler // ResourcesImpl constructions. final int diff = activity.mCurrentConfig.diffPublicOnly(newConfig); - if (diff == 0 && !shouldUpdateWindowMetricsBounds(activity.mCurrentConfig, newConfig) - && !movedToDifferentDisplay && mResourcesManager.isSameResourcesOverrideConfig( - activityToken, amOverrideConfig)) { - // Nothing significant, don't proceed with updating and reporting. - return null; + if (diff == 0) { + if (!shouldUpdateWindowMetricsBounds(activity.mCurrentConfig, newConfig) + && !movedToDifferentDisplay + && mResourcesManager.isSameResourcesOverrideConfig( + activityToken, amOverrideConfig)) { + // Nothing significant, don't proceed with updating and reporting. + return null; + } } else if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) { // If this activity doesn't handle any of the config changes, then don't bother // calling onConfigurationChanged. Otherwise, report to the activity for the diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index a6260d6d9cad..dba62b9d3b63 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -3228,6 +3228,12 @@ public class ApplicationPackageManager extends PackageManager { @Override public void registerDexModule(@NonNull String dexModule, @Nullable DexModuleRegisterCallback callback) { + // Create the callback delegate to be passed to package manager service. + DexModuleRegisterCallbackDelegate callbackDelegate = null; + if (callback != null) { + callbackDelegate = new DexModuleRegisterCallbackDelegate(callback); + } + // Check if this is a shared module by looking if the others can read it. boolean isSharedModule = false; try { @@ -3236,18 +3242,13 @@ public class ApplicationPackageManager extends PackageManager { isSharedModule = true; } } catch (ErrnoException e) { - callback.onDexModuleRegistered(dexModule, false, - "Could not get stat the module file: " + e.getMessage()); + if (callbackDelegate != null) { + callback.onDexModuleRegistered(dexModule, false, + "Could not get stat the module file: " + e.getMessage()); + } return; } - // Module path is ok. - // Create the callback delegate to be passed to package manager service. - DexModuleRegisterCallbackDelegate callbackDelegate = null; - if (callback != null) { - callbackDelegate = new DexModuleRegisterCallbackDelegate(callback); - } - // Invoke the package manager service. try { mPM.registerDexModule(mContext.getPackageName(), dexModule, diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index be426aa7ed2b..83d0246744df 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -1110,6 +1110,10 @@ public final class LoadedApk { mPackageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.myUserId()); + if (pi == null) { + throw new IllegalStateException("Unable to get package info for " + + mPackageName + "; is package not installed?"); + } /* * Two possible indications that this package could be * sharing its virtual machine with other packages: diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index b00cfcb0d020..2b45723dae55 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1611,7 +1611,8 @@ public class Notification implements Parcelable /** * {@code SemanticAction}: Mark the conversation associated with the notification as a - * priority. Note that this is only for use by the notification assistant services. + * priority. Note that this is only for use by the notification assistant services. The + * type will be ignored for actions an app adds to its own notifications. * @hide */ @SystemApi @@ -1619,7 +1620,8 @@ public class Notification implements Parcelable /** * {@code SemanticAction}: Mark content as a potential phishing attempt. - * Note that this is only for use by the notification assistant services. + * Note that this is only for use by the notification assistant services. The type will + * be ignored for actions an app adds to its own notifications. * @hide */ @SystemApi @@ -5015,11 +5017,14 @@ public class Notification implements Parcelable } if (p.text != null && p.text.length() != 0 && (!showProgress || p.mAllowTextWithProgress)) { - int textId = com.android.internal.R.id.text; - contentView.setTextViewText(textId, processTextSpans(p.text)); - setTextViewColorSecondary(contentView, textId, p); - contentView.setViewVisibility(textId, View.VISIBLE); + contentView.setViewVisibility(p.mTextViewId, View.VISIBLE); + contentView.setTextViewText(p.mTextViewId, processTextSpans(p.text)); + setTextViewColorSecondary(contentView, p.mTextViewId, p); hasSecondLine = true; + } else if (p.mTextViewId != R.id.text) { + // This alternate text view ID is not cleared by resetStandardTemplate + contentView.setViewVisibility(p.mTextViewId, View.GONE); + contentView.setTextViewText(p.mTextViewId, null); } setHeaderlessVerticalMargins(contentView, p, hasSecondLine); @@ -5211,6 +5216,9 @@ public class Notification implements Parcelable // views in states with a header (big states) result.mHeadingExtraMarginSet.applyToView(contentView, R.id.notification_header); result.mTitleMarginSet.applyToView(contentView, R.id.title); + // If there is no title, the text (or big_text) needs to wrap around the image + result.mTitleMarginSet.applyToView(contentView, p.mTextViewId); + contentView.setInt(p.mTextViewId, "setNumIndentLines", p.hasTitle() ? 0 : 1); } } @@ -5443,8 +5451,12 @@ public class Notification implements Parcelable return p.allowColorization && mN.isColorized(); } - private boolean isCallActionColorCustomizable(StandardTemplateParams p) { - return isColorized(p) && mContext.getResources().getBoolean( + private boolean isCallActionColorCustomizable() { + // NOTE: this doesn't need to check StandardTemplateParams.allowColorization because + // that is only used for disallowing colorization of headers for the minimized state, + // and neither of those conditions applies when showing actions. + // Not requiring StandardTemplateParams as an argument simplifies the creation process. + return mN.isColorized() && mContext.getResources().getBoolean( R.bool.config_callNotificationActionColorsRequireColorized); } @@ -5510,13 +5522,13 @@ public class Notification implements Parcelable */ private @NonNull List<Notification.Action> getNonContextualActions() { if (mActions == null) return Collections.emptyList(); - List<Notification.Action> contextualActions = new ArrayList<>(); + List<Notification.Action> standardActions = new ArrayList<>(); for (Notification.Action action : mActions) { if (!action.isContextual()) { - contextualActions.add(action); + standardActions.add(action); } } - return contextualActions; + return standardActions; } private RemoteViews applyStandardTemplateWithActions(int layoutId, @@ -5536,16 +5548,29 @@ public class Notification implements Parcelable // filter them out here. List<Notification.Action> nonContextualActions = getNonContextualActions(); - int N = nonContextualActions.size(); - boolean emphazisedMode = mN.fullScreenIntent != null; + int numActions = Math.min(nonContextualActions.size(), MAX_ACTION_BUTTONS); + boolean emphazisedMode = mN.fullScreenIntent != null || p.mCallStyleActions; + if (p.mCallStyleActions) { + // Clear view padding to allow buttons to start on the left edge. + // This must be done before 'setEmphasizedMode' which sets top/bottom margins. + big.setViewPadding(R.id.actions, 0, 0, 0, 0); + // Add an optional indent that will make buttons start at the correct column when + // there is enough space to do so (and fall back to the left edge if not). + big.setInt(R.id.actions, "setCollapsibleIndentDimen", + R.dimen.call_notification_collapsible_indent); + } big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode); - if (N > 0 && !p.mHideActions) { + if (p.mCallStyleActions) { + // Use "wrap_content" (unlike normal emphasized mode) and allow prioritizing the + // required actions (Answer, Decline, and Hang Up). + big.setBoolean(R.id.actions, "setPrioritizedWrapMode", true); + } + if (numActions > 0 && !p.mHideActions) { big.setViewVisibility(R.id.actions_container, View.VISIBLE); big.setViewVisibility(R.id.actions, View.VISIBLE); big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target, RemoteViews.MARGIN_BOTTOM, 0); - if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS; - for (int i=0; i<N; i++) { + for (int i = 0; i < numActions; i++) { Action action = nonContextualActions.get(i); boolean actionHasValidInput = hasValidRemoteInput(action); @@ -5556,6 +5581,11 @@ public class Notification implements Parcelable // Clear the drawable button.setInt(R.id.action0, "setBackgroundResource", 0); } + if (p.mCallStyleActions && i > 0) { + // Clear start margin from non-first buttons to reduce the gap between them. + // (8dp remaining gap is from all buttons' standard 4dp inset). + button.setViewLayoutMarginDimen(R.id.action0, RemoteViews.MARGIN_START, 0); + } big.addView(R.id.actions, button); } } else { @@ -5773,11 +5803,11 @@ public class Notification implements Parcelable if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S) { return true; } - // If the big content view has no content, we can exempt the app from having to show it. + // Notifications with contentView and without a bigContentView, style, or actions would + // not have an expanded state before S, so showing the standard template expanded state + // usually looks wrong, so we keep it simple and don't show the expanded state. boolean exempt = mN.contentView != null && mN.bigContentView == null - && mStyle == null && mActions.size() == 0 - && mN.extras.getCharSequence(EXTRA_TITLE) == null - && mN.extras.getCharSequence(EXTRA_TEXT) == null; + && mStyle == null && mActions.size() == 0; return !exempt; } @@ -6017,7 +6047,7 @@ public class Notification implements Parcelable button.setColorStateList(R.id.action0, "setButtonBackground", ColorStateList.valueOf(background)); button.setBoolean(R.id.action0, "setHasStroke", !hasColorOverride); - if (p.mAllowActionIcons) { + if (p.mCallStyleActions) { button.setImageViewIcon(R.id.action0, action.getIcon()); boolean priority = action.getExtras().getBoolean(CallStyle.KEY_ACTION_PRIORITY); button.setBoolean(R.id.action0, "setWrapModePriority", priority); @@ -7014,16 +7044,7 @@ public class Notification implements Parcelable p.title = mBigContentTitle; } - RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId, p, - result); - - if (mBigContentTitle != null && mBigContentTitle.equals("")) { - contentView.setViewVisibility(R.id.title, View.GONE); - } else { - contentView.setViewVisibility(R.id.title, View.VISIBLE); - } - - return contentView; + return mBuilder.applyStandardTemplateWithActions(layoutId, p, result); } /** @@ -7616,22 +7637,16 @@ public class Notification implements Parcelable public RemoteViews makeBigContentView() { StandardTemplateParams p = mBuilder.mParams.reset() .viewType(StandardTemplateParams.VIEW_TYPE_BIG) - .fillTextsFrom(mBuilder).text(null); - RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource(), p, null); + .textViewId(R.id.big_text) + .fillTextsFrom(mBuilder); + // Replace the text with the big text, but only if the big text is not empty. CharSequence bigTextText = mBuilder.processLegacyText(mBigText); - if (TextUtils.isEmpty(bigTextText)) { - // In case the bigtext is null / empty fall back to the normal text to avoid a weird - // experience - bigTextText = mBuilder.processLegacyText( - mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT)); + if (!TextUtils.isEmpty(bigTextText)) { + p.text(bigTextText); } - contentView.setTextViewText(R.id.big_text, mBuilder.processTextSpans(bigTextText)); - mBuilder.setTextViewColorSecondary(contentView, R.id.big_text, p); - contentView.setViewVisibility(R.id.big_text, - TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE); - return contentView; + return getStandardView(mBuilder.getBigTextLayoutResource(), p, null /* result */); } /** @@ -9263,6 +9278,17 @@ public class Notification implements Parcelable return this; } + /** @hide */ + @Override + public Notification buildStyled(Notification wip) { + wip = super.buildStyled(wip); + // ensure that the actions in the builder and notification are corrected. + mBuilder.mActions = getActionsListWithSystemActions(); + wip.actions = new Action[mBuilder.mActions.size()]; + mBuilder.mActions.toArray(wip.actions); + return wip; + } + /** * @hide */ @@ -9322,14 +9348,14 @@ public class Notification implements Parcelable } @NonNull - private Action makeNegativeAction(@NonNull StandardTemplateParams p) { + private Action makeNegativeAction() { if (mDeclineIntent == null) { - return makeAction(p, R.drawable.ic_call_decline, + return makeAction(R.drawable.ic_call_decline, R.string.call_notification_hang_up_action, mDeclineButtonColor, R.color.call_notification_decline_color, mHangUpIntent); } else { - return makeAction(p, R.drawable.ic_call_decline, + return makeAction(R.drawable.ic_call_decline, R.string.call_notification_decline_action, mDeclineButtonColor, R.color.call_notification_decline_color, mDeclineIntent); @@ -9337,18 +9363,17 @@ public class Notification implements Parcelable } @Nullable - private Action makeAnswerAction(@NonNull StandardTemplateParams p) { - return mAnswerIntent == null ? null : makeAction(p, R.drawable.ic_call_answer, + private Action makeAnswerAction() { + return mAnswerIntent == null ? null : makeAction(R.drawable.ic_call_answer, R.string.call_notification_answer_action, mAnswerButtonColor, R.color.call_notification_answer_color, mAnswerIntent); } @NonNull - private Action makeAction(@NonNull StandardTemplateParams p, - @DrawableRes int icon, @StringRes int title, + private Action makeAction(@DrawableRes int icon, @StringRes int title, @ColorInt Integer colorInt, @ColorRes int defaultColorRes, PendingIntent intent) { - if (colorInt == null || !mBuilder.isCallActionColorCustomizable(p)) { + if (colorInt == null || !mBuilder.isCallActionColorCustomizable()) { colorInt = mBuilder.mContext.getColor(defaultColorRes); } Action action = new Action.Builder(Icon.createWithResource("", icon), @@ -9360,29 +9385,62 @@ public class Notification implements Parcelable return action; } - private ArrayList<Action> makeActionsList(@NonNull StandardTemplateParams p) { - final Action negativeAction = makeNegativeAction(p); - final Action answerAction = makeAnswerAction(p); + private boolean isActionAddedByCallStyle(Action action) { + // This is an internal extra added by the style to these actions. If an app were to add + // this extra to the action themselves, the action would be dropped. :shrug: + return action != null && action.getExtras().getBoolean(KEY_ACTION_PRIORITY); + } - ArrayList<Action> actions = new ArrayList<>(MAX_ACTION_BUTTONS); - final Action lastAction; - if (answerAction == null) { - // If there's no answer action, put the hang up / decline action at the end - lastAction = negativeAction; - } else { - // Otherwise put the answer action at the end, and put the decline action at start. - actions.add(negativeAction); - lastAction = answerAction; - } - // For consistency with the standard actions bar, contextual actions are ignored. - for (Action action : mBuilder.getNonContextualActions()) { - if (actions.size() >= MAX_ACTION_BUTTONS - 1) { - break; + /** + * Gets the actions list for the call with the answer/decline/hangUp actions inserted in + * the correct place. This returns the correct result even if the system actions have + * already been added, and even if more actions were added since then. + * @hide + */ + @NonNull + public ArrayList<Action> getActionsListWithSystemActions() { + // Define the system actions we expect to see + final Action negativeAction = makeNegativeAction(); + final Action answerAction = makeAnswerAction(); + // Sort the expected actions into the correct order: + // * If there's no answer action, put the hang up / decline action at the end + // * Otherwise put the answer action at the end, and put the decline action at start. + final Action firstAction = answerAction == null ? null : negativeAction; + final Action lastAction = answerAction == null ? negativeAction : answerAction; + + // Start creating the result list. + int nonContextualActionSlotsRemaining = MAX_ACTION_BUTTONS; + ArrayList<Action> resultActions = new ArrayList<>(MAX_ACTION_BUTTONS); + if (firstAction != null) { + resultActions.add(firstAction); + --nonContextualActionSlotsRemaining; + } + + // Copy actions into the new list, correcting system actions. + if (mBuilder.mActions != null) { + for (Notification.Action action : mBuilder.mActions) { + if (action.isContextual()) { + // Always include all contextual actions + resultActions.add(action); + } else if (isActionAddedByCallStyle(action)) { + // Drop any old versions of system actions + } else { + // Copy non-contextual actions; decrement the remaining action slots. + resultActions.add(action); + --nonContextualActionSlotsRemaining; + } + // If there's exactly one action slot left, fill it with the lastAction. + if (nonContextualActionSlotsRemaining == 1) { + resultActions.add(lastAction); + --nonContextualActionSlotsRemaining; + } } - actions.add(action); } - actions.add(lastAction); - return actions; + // If there are any action slots left, the lastAction still needs to be added. + if (nonContextualActionSlotsRemaining >= 1) { + resultActions.add(lastAction); + } + return resultActions; } private RemoteViews makeCallLayout() { @@ -9395,19 +9453,15 @@ public class Notification implements Parcelable // Bind standard template StandardTemplateParams p = mBuilder.mParams.reset() .viewType(StandardTemplateParams.VIEW_TYPE_BIG) - .allowActionIcons(true) + .callStyleActions(true) .allowTextWithProgress(true) .hideLargeIcon(true) .text(text) .summaryText(mBuilder.processLegacyText(mVerificationText)); - RemoteViews contentView = mBuilder.applyStandardTemplate( + mBuilder.mActions = getActionsListWithSystemActions(); + RemoteViews contentView = mBuilder.applyStandardTemplateWithActions( mBuilder.getCallLayoutResource(), p, null /* result */); - // Bind actions. - mBuilder.resetStandardTemplateWithActions(contentView); - mBuilder.bindSnoozeAction(contentView, p); - bindCallActions(contentView, p); - // Bind some extra conversation-specific header fields. mBuilder.setTextViewColorPrimary(contentView, R.id.conversation_text, p); mBuilder.setTextViewColorSecondary(contentView, R.id.app_name_divider, p); @@ -9427,41 +9481,6 @@ public class Notification implements Parcelable return contentView; } - private void bindCallActions(RemoteViews view, StandardTemplateParams p) { - view.setViewVisibility(R.id.actions_container, View.VISIBLE); - view.setViewVisibility(R.id.actions, View.VISIBLE); - view.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target, - RemoteViews.MARGIN_BOTTOM, 0); - - // Clear view padding to allow buttons to start on the left edge. - // This must be done before 'setEmphasizedMode' which sets top/bottom margins. - view.setViewPadding(R.id.actions, 0, 0, 0, 0); - // Add an optional indent that will make buttons start at the correct column when - // there is enough space to do so (and fall back to the left edge if not). - view.setInt(R.id.actions, "setCollapsibleIndentDimen", - R.dimen.call_notification_collapsible_indent); - - // Emphasize so that buttons have borders or colored backgrounds - boolean emphasizedMode = true; - view.setBoolean(R.id.actions, "setEmphasizedMode", emphasizedMode); - // Use "wrap_content" (unlike normal emphasized mode) and allow prioritizing the - // required actions (Answer, Decline, and Hang Up). - view.setBoolean(R.id.actions, "setPrioritizedWrapMode", true); - - // Create the buttons for the generated actions list. - int i = 0; - for (Action action : makeActionsList(p)) { - final RemoteViews button = mBuilder.generateActionButton(action, emphasizedMode, p); - if (i > 0) { - // Clear start margin from non-first buttons to reduce the gap between buttons. - // (8dp remaining gap is from all buttons' standard 4dp inset). - button.setViewLayoutMarginDimen(R.id.action0, RemoteViews.MARGIN_START, 0); - } - view.addView(R.id.actions, button); - ++i; - } - } - private void bindCallerVerification(RemoteViews contentView, StandardTemplateParams p) { String iconContentDescription = null; boolean showDivider = true; @@ -12083,6 +12102,21 @@ public class Notification implements Parcelable if (viewId == R.id.notification_header) { views.setFloat(R.id.notification_header, "setTopLineExtraMarginEndDp", marginEndDp); + } else if (viewId == R.id.text || viewId == R.id.big_text) { + if (mValueIfGone != 0) { + throw new RuntimeException("Programming error: `text` and `big_text` use " + + "ImageFloatingTextView which can either show a margin or not; " + + "thus mValueIfGone must be 0, but it was " + mValueIfGone); + } + // Note that the caller must set "setNumIndentLines" to a positive int in order + // for this margin to do anything at all. + views.setFloat(viewId, "setImageEndMarginDp", mValueIfVisible); + views.setBoolean(viewId, "setHasImage", mRightIconVisible); + // Apply just the *extra* margin as the view layout margin; this will be + // unchanged depending on the visibility of the image, but it means that the + // extra margin applies to *every* line of text instead of just indented lines. + views.setViewLayoutMargin(viewId, RemoteViews.MARGIN_END, + extraMarginDp, TypedValue.COMPLEX_UNIT_DIP); } else { views.setViewLayoutMargin(viewId, RemoteViews.MARGIN_END, marginEndDp, TypedValue.COMPLEX_UNIT_DIP); @@ -12119,8 +12153,9 @@ public class Notification implements Parcelable boolean mHideProgress; boolean mHideSnoozeButton; boolean mPromotePicture; - boolean mAllowActionIcons; + boolean mCallStyleActions; boolean mAllowTextWithProgress; + int mTextViewId; CharSequence title; CharSequence text; CharSequence headerTextSecondary; @@ -12138,8 +12173,9 @@ public class Notification implements Parcelable mHideProgress = false; mHideSnoozeButton = false; mPromotePicture = false; - mAllowActionIcons = false; + mCallStyleActions = false; mAllowTextWithProgress = false; + mTextViewId = R.id.text; title = null; text = null; summaryText = null; @@ -12179,8 +12215,8 @@ public class Notification implements Parcelable return this; } - final StandardTemplateParams allowActionIcons(boolean allowActionIcons) { - this.mAllowActionIcons = allowActionIcons; + final StandardTemplateParams callStyleActions(boolean callStyleActions) { + this.mCallStyleActions = callStyleActions; return this; } @@ -12199,6 +12235,11 @@ public class Notification implements Parcelable return this; } + public StandardTemplateParams textViewId(int textViewId) { + mTextViewId = textViewId; + return this; + } + final StandardTemplateParams title(CharSequence title) { this.title = title; return this; diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 8e53b5ba1c9f..7dbbc54665e9 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -57,6 +57,7 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.DeadSystemException; +import android.os.Environment; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; @@ -120,6 +121,8 @@ public class WallpaperManager { /** {@hide} */ private static final String VALUE_CMF_COLOR = android.os.SystemProperties.get("ro.boot.hardware.color"); + /** {@hide} */ + private static final String WALLPAPER_CMF_PATH = "/wallpaper/image/"; /** * Activity Action: Show settings for choosing wallpaper. Do not use directly to construct @@ -2066,31 +2069,45 @@ public class WallpaperManager { return null; } else { whichProp = PROP_WALLPAPER; - final int defaultColorResId = context.getResources().getIdentifier( - "default_wallpaper_" + VALUE_CMF_COLOR, "drawable", "android"); - defaultResId = - defaultColorResId == 0 ? com.android.internal.R.drawable.default_wallpaper - : defaultColorResId; + defaultResId = com.android.internal.R.drawable.default_wallpaper; } final String path = SystemProperties.get(whichProp); + final InputStream wallpaperInputStream = getWallpaperInputStream(path); + if (wallpaperInputStream != null) { + return wallpaperInputStream; + } + final String cmfPath = getCmfWallpaperPath(); + final InputStream cmfWallpaperInputStream = getWallpaperInputStream(cmfPath); + if (cmfWallpaperInputStream != null) { + return cmfWallpaperInputStream; + } + try { + return context.getResources().openRawResource(defaultResId); + } catch (NotFoundException e) { + // no default defined for this device; this is not a failure + } + return null; + } + + private static InputStream getWallpaperInputStream(String path) { if (!TextUtils.isEmpty(path)) { final File file = new File(path); if (file.exists()) { try { return new FileInputStream(file); } catch (IOException e) { - // Ignored, fall back to platform default below + // Ignored, fall back to platform default } } } - try { - return context.getResources().openRawResource(defaultResId); - } catch (NotFoundException e) { - // no default defined for this device; this is not a failure - } return null; } + private static String getCmfWallpaperPath() { + return Environment.getProductDirectory() + WALLPAPER_CMF_PATH + "default_wallpaper_" + + VALUE_CMF_COLOR; + } + /** * Return {@link ComponentName} of the default live wallpaper, or * {@code null} if none is defined. diff --git a/core/java/android/app/WindowTokenClient.java b/core/java/android/app/WindowTokenClient.java index 29792ac47a36..2298e84d755e 100644 --- a/core/java/android/app/WindowTokenClient.java +++ b/core/java/android/app/WindowTokenClient.java @@ -85,8 +85,10 @@ public class WindowTokenClient extends IWindowToken.Stub { context.destroy(); mContextRef.clear(); } - // If a secondary display is detached, release all views attached to this token. - WindowManagerGlobal.getInstance().closeAll(this, mContextRef.getClass().getName(), - "WindowContext"); + ActivityThread.currentActivityThread().getHandler().post(() -> { + // If the tracked window token is detached, release all views attached to this token. + WindowManagerGlobal.getInstance().closeAll(WindowTokenClient.this, + "#onWindowTokenRemoved()", "WindowTokenClient"); + }); } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index ccf41e5f3063..930717b97555 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -987,7 +987,8 @@ public class DevicePolicyManager { * The default for this extra is {@code false} - by default, the admin of a fully-managed * device has the ability to grant sensors-related permissions. * - * <p>Use with {@link #ACTION_PROVISION_MANAGED_DEVICE} only. + * <p>Use only for device owner provisioning. + * @see #ACTION_GET_PROVISIONING_MODE */ public static final String EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT = "android.app.extra.PROVISIONING_PERMISSION_GRANT_OPT_OUT"; @@ -11838,7 +11839,7 @@ public class DevicePolicyManager { /** * @hide - * Force update user setup completed status. This API has no effect on user build. + * Force update user setup completed status. * @throws {@link SecurityException} if the caller has no * {@code android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS} or the caller is * not {@link UserHandle#SYSTEM_USER} @@ -13725,4 +13726,22 @@ public class DevicePolicyManager { throw re.rethrowFromSystemServer(); } } + + /** + * Lists apps that are exempt from policies (such as + * {@link #setPackagesSuspended(ComponentName, String[], boolean)}). + * + * @hide + */ + @TestApi + @RequiresPermission(value = android.Manifest.permission.MANAGE_DEVICE_ADMINS) + public @NonNull Set<String> getPolicyExemptApps() { + if (mService == null) return Collections.emptySet(); + + try { + return new HashSet<>(mService.listPolicyExemptApps()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 25ca59963d4b..e98720c0d96c 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -177,6 +177,7 @@ interface IDevicePolicyManager { String[] setPackagesSuspended(in ComponentName admin, in String callerPackage, in String[] packageNames, boolean suspended); boolean isPackageSuspended(in ComponentName admin, in String callerPackage, String packageName); + List<String> listPolicyExemptApps(); boolean installCaCert(in ComponentName admin, String callerPackage, in byte[] certBuffer); void uninstallCaCerts(in ComponentName admin, String callerPackage, in String[] aliases); diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index d79fac58cf12..8fd0de7dbb39 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -849,6 +849,7 @@ public class AppWidgetHostView extends FrameLayout { public void setColorResources(@NonNull SparseIntArray colorMapping) { mColorResources = RemoteViews.ColorResources.create(mContext, colorMapping); mLayoutId = -1; + mViewMode = VIEW_MODE_NOINIT; reapplyLastRemoteViews(); } @@ -863,6 +864,7 @@ public class AppWidgetHostView extends FrameLayout { if (mColorResources != null) { mColorResources = null; mLayoutId = -1; + mViewMode = VIEW_MODE_NOINIT; reapplyLastRemoteViews(); } } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index df5c58c2634f..0509e3f77c1f 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4837,6 +4837,15 @@ public abstract class Context { public static final String POWER_WHITELIST_MANAGER = "power_whitelist"; /** + * System service name for the PowerExemptionManager. + * + * @see #getSystemService(String) + * @hide + */ + @SystemApi + public static final String POWER_EXEMPTION_SERVICE = "power_exemption"; + + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link android.app.admin.DevicePolicyManager} for working with global * device policy management. diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index de17fda82d71..04f93ca6991b 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2331,6 +2331,7 @@ public class Intent implements Parcelable, Cloneable { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE"; /** * Alarm Changed Action: This is broadcast when the AlarmClock diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java index 1c21b2aa73a5..47c333ceb931 100644 --- a/core/java/android/content/SyncAdapterType.java +++ b/core/java/android/content/SyncAdapterType.java @@ -17,6 +17,7 @@ package android.content; import android.annotation.Nullable; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; @@ -168,6 +169,7 @@ public class SyncAdapterType implements Parcelable { * * @hide */ + @TestApi public @Nullable String getPackageName() { return packageName; } diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 1660c9d23002..58f83a73ff16 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -892,22 +892,42 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { */ @ChangeId @Disabled - public static final long FORCE_RESIZE_APP = 174042936L; // number refers to buganizer id + @TestApi + public static final long FORCE_RESIZE_APP = 174042936L; // buganizer id + + /** + * This change id forces the packages it is applied to to be non-resizable. + * @hide + */ + @ChangeId + @Disabled + @TestApi + public static final long FORCE_NON_RESIZE_APP = 181136395L; // buganizer id /** * Return value for {@link #supportsSizeChanges()} indicating that this activity does not - * support size changes. + * support size changes due to the android.supports_size_changes metadata flag either being + * unset or set to {@code false} on application or activity level. + * + * @hide + */ + public static final int SIZE_CHANGES_UNSUPPORTED_METADATA = 0; + + /** + * Return value for {@link #supportsSizeChanges()} indicating that this activity has been + * overridden to not support size changes through the compat framework change id + * {@link #FORCE_NON_RESIZE_APP}. * @hide */ - public static final int SIZE_CHANGES_UNSUPPORTED = 0; + public static final int SIZE_CHANGES_UNSUPPORTED_OVERRIDE = 1; /** * Return value for {@link #supportsSizeChanges()} indicating that this activity supports size - * changes due to the android.supports_size_changes metadata flag being set either on - * application or on activity level. + * changes due to the android.supports_size_changes metadata flag being set to {@code true} + * either on application or activity level. * @hide */ - public static final int SIZE_CHANGES_SUPPORTED_METADATA = 1; + public static final int SIZE_CHANGES_SUPPORTED_METADATA = 2; /** * Return value for {@link #supportsSizeChanges()} indicating that this activity has been @@ -915,11 +935,12 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * {@link #FORCE_RESIZE_APP}. * @hide */ - public static final int SIZE_CHANGES_SUPPORTED_OVERRIDE = 2; + public static final int SIZE_CHANGES_SUPPORTED_OVERRIDE = 3; /** @hide */ @IntDef(prefix = { "SIZE_CHANGES_" }, value = { - SIZE_CHANGES_UNSUPPORTED, + SIZE_CHANGES_UNSUPPORTED_METADATA, + SIZE_CHANGES_UNSUPPORTED_OVERRIDE, SIZE_CHANGES_SUPPORTED_METADATA, SIZE_CHANGES_SUPPORTED_OVERRIDE, }) @@ -1065,6 +1086,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { */ public WindowLayout windowLayout; + /** + * Attribution tags for finer grained calls if a {@android.content.Context#sendBroadcast(Intent, + * String)} is used with a permission. + * @hide + */ + public String[] attributionTags; + public ActivityInfo() { } @@ -1093,6 +1121,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { maxAspectRatio = orig.maxAspectRatio; minAspectRatio = orig.minAspectRatio; supportsSizeChanges = orig.supportsSizeChanges; + attributionTags = orig.attributionTags; } /** @@ -1213,6 +1242,12 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { */ @SizeChangesSupportMode public int supportsSizeChanges() { + if (CompatChanges.isChangeEnabled(FORCE_NON_RESIZE_APP, + applicationInfo.packageName, + UserHandle.getUserHandleForUid(applicationInfo.uid))) { + return SIZE_CHANGES_UNSUPPORTED_OVERRIDE; + } + if (supportsSizeChanges) { return SIZE_CHANGES_SUPPORTED_METADATA; } @@ -1223,7 +1258,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { return SIZE_CHANGES_SUPPORTED_OVERRIDE; } - return SIZE_CHANGES_UNSUPPORTED; + return SIZE_CHANGES_UNSUPPORTED_METADATA; } /** @hide */ @@ -1269,8 +1304,10 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { /** @hide */ public static String sizeChangesSupportModeToString(@SizeChangesSupportMode int mode) { switch (mode) { - case SIZE_CHANGES_UNSUPPORTED: - return "SIZE_CHANGES_UNSUPPORTED"; + case SIZE_CHANGES_UNSUPPORTED_METADATA: + return "SIZE_CHANGES_UNSUPPORTED_METADATA"; + case SIZE_CHANGES_UNSUPPORTED_OVERRIDE: + return "SIZE_CHANGES_UNSUPPORTED_OVERRIDE"; case SIZE_CHANGES_SUPPORTED_METADATA: return "SIZE_CHANGES_SUPPORTED_METADATA"; case SIZE_CHANGES_SUPPORTED_OVERRIDE: @@ -1332,6 +1369,15 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { if (supportsSizeChanges) { pw.println(prefix + "supportsSizeChanges=true"); } + if (attributionTags != null && attributionTags.length > 0) { + StringBuilder tags = new StringBuilder(); + tags.append(attributionTags[0]); + for (int i = 1; i < attributionTags.length; i++) { + tags.append(", "); + tags.append(attributionTags[i]); + } + pw.println(prefix + "attributionTags=[" + tags + "]"); + } super.dumpBack(pw, prefix, dumpFlags); } @@ -1377,6 +1423,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { dest.writeFloat(maxAspectRatio); dest.writeFloat(minAspectRatio); dest.writeBoolean(supportsSizeChanges); + dest.writeString8Array(attributionTags); } /** @@ -1496,6 +1543,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { maxAspectRatio = source.readFloat(); minAspectRatio = source.readFloat(); supportsSizeChanges = source.readBoolean(); + attributionTags = source.createString8Array(); } /** diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java index 0d5b33cd8672..8f9a0d79f33b 100644 --- a/core/java/android/content/pm/dex/DexMetadataHelper.java +++ b/core/java/android/content/pm/dex/DexMetadataHelper.java @@ -29,6 +29,7 @@ import android.util.Log; import android.util.jar.StrictJarFile; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.security.VerityUtils; import java.io.File; import java.io.IOException; @@ -76,7 +77,8 @@ public class DexMetadataHelper { * Returns whether fs-verity is required to install a dex metadata */ public static boolean isFsVerityRequired() { - return SystemProperties.getBoolean(PROPERTY_DM_FSVERITY_REQUIRED, false); + return VerityUtils.isFsVeritySupported() + && SystemProperties.getBoolean(PROPERTY_DM_FSVERITY_REQUIRED, false); } /** diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java index 9a84ded99c67..b660a00443a4 100644 --- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java +++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java @@ -482,6 +482,7 @@ public class PackageInfoWithoutStateUtils { ai.rotationAnimation = a.getRotationAnimation(); ai.colorMode = a.getColorMode(); ai.windowLayout = a.getWindowLayout(); + ai.attributionTags = a.getAttributionTags(); if ((flags & PackageManager.GET_META_DATA) != 0) { ai.metaData = a.getMetaData(); } diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java index 6f478accedd7..9285ccb3cf0c 100644 --- a/core/java/android/content/pm/parsing/component/ParsedActivity.java +++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java @@ -82,6 +82,9 @@ public class ParsedActivity extends ParsedMainComponent { @Nullable ActivityInfo.WindowLayout windowLayout; + @Nullable + String[] attributionTags; + public ParsedActivity(ParsedActivity other) { super(other); this.theme = other.theme; @@ -107,6 +110,7 @@ public class ParsedActivity extends ParsedMainComponent { this.rotationAnimation = other.rotationAnimation; this.colorMode = other.colorMode; this.windowLayout = other.windowLayout; + this.attributionTags = other.attributionTags; } /** @@ -172,6 +176,7 @@ public class ParsedActivity extends ParsedMainComponent { alias.requestedVrComponent = target.requestedVrComponent; alias.directBootAware = target.directBootAware; alias.setProcessName(target.getProcessName()); + alias.attributionTags = target.attributionTags; return alias; // Not all attributes from the target ParsedActivity are copied to the alias. @@ -299,6 +304,7 @@ public class ParsedActivity extends ParsedMainComponent { } else { dest.writeBoolean(false); } + dest.writeString8Array(this.attributionTags); } public ParsedActivity() { @@ -332,6 +338,7 @@ public class ParsedActivity extends ParsedMainComponent { if (in.readBoolean()) { windowLayout = new ActivityInfo.WindowLayout(in); } + this.attributionTags = in.createString8Array(); } public static final Parcelable.Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() { @@ -445,4 +452,9 @@ public class ParsedActivity extends ParsedMainComponent { public ActivityInfo.WindowLayout getWindowLayout() { return windowLayout; } + + @Nullable + public String[] getAttributionTags() { + return attributionTags; + } } diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java index 0f4aa061b72d..d99c4109e5ad 100644 --- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java @@ -210,6 +210,11 @@ public class ParsedActivityUtils { pkg.setVisibleToInstantApps(true); } + String attributionTags = sa.getString(R.styleable.AndroidManifestActivity_attributionTags); + if (attributionTags != null) { + activity.attributionTags = attributionTags.split("\\|"); + } + return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver, false /*isAlias*/, visibleToEphemeral, input, R.styleable.AndroidManifestActivity_parentActivityName, diff --git a/core/java/android/ddm/DdmHandleHeap.java b/core/java/android/ddm/DdmHandleHeap.java index e24aeb2af3a1..8fa235294451 100644 --- a/core/java/android/ddm/DdmHandleHeap.java +++ b/core/java/android/ddm/DdmHandleHeap.java @@ -30,15 +30,7 @@ import java.nio.ByteBuffer; */ public class DdmHandleHeap extends ChunkHandler { - public static final int CHUNK_HPIF = type("HPIF"); - public static final int CHUNK_HPSG = type("HPSG"); - public static final int CHUNK_HPDU = type("HPDU"); - public static final int CHUNK_HPDS = type("HPDS"); - public static final int CHUNK_NHSG = type("NHSG"); public static final int CHUNK_HPGC = type("HPGC"); - public static final int CHUNK_REAE = type("REAE"); - public static final int CHUNK_REAQ = type("REAQ"); - public static final int CHUNK_REAL = type("REAL"); private static DdmHandleHeap mInstance = new DdmHandleHeap(); @@ -50,15 +42,7 @@ public class DdmHandleHeap extends ChunkHandler { * Register for the messages we're interested in. */ public static void register() { - DdmServer.registerHandler(CHUNK_HPIF, mInstance); - DdmServer.registerHandler(CHUNK_HPSG, mInstance); - DdmServer.registerHandler(CHUNK_HPDU, mInstance); - DdmServer.registerHandler(CHUNK_HPDS, mInstance); - DdmServer.registerHandler(CHUNK_NHSG, mInstance); DdmServer.registerHandler(CHUNK_HPGC, mInstance); - DdmServer.registerHandler(CHUNK_REAE, mInstance); - DdmServer.registerHandler(CHUNK_REAQ, mInstance); - DdmServer.registerHandler(CHUNK_REAL, mInstance); } /** @@ -81,24 +65,8 @@ public class DdmHandleHeap extends ChunkHandler { Log.v("ddm-heap", "Handling " + name(request.type) + " chunk"); int type = request.type; - if (type == CHUNK_HPIF) { - return handleHPIF(request); - } else if (type == CHUNK_HPSG) { - return handleHPSGNHSG(request, false); - } else if (type == CHUNK_HPDU) { - return handleHPDU(request); - } else if (type == CHUNK_HPDS) { - return handleHPDS(request); - } else if (type == CHUNK_NHSG) { - return handleHPSGNHSG(request, true); - } else if (type == CHUNK_HPGC) { + if (type == CHUNK_HPGC) { return handleHPGC(request); - } else if (type == CHUNK_REAE) { - return handleREAE(request); - } else if (type == CHUNK_REAQ) { - return handleREAQ(request); - } else if (type == CHUNK_REAL) { - return handleREAL(request); } else { throw new RuntimeException("Unknown packet " + ChunkHandler.name(type)); @@ -106,112 +74,6 @@ public class DdmHandleHeap extends ChunkHandler { } /* - * Handle a "HeaP InFo" request. - */ - private Chunk handleHPIF(Chunk request) { - ByteBuffer in = wrapChunk(request); - - int when = in.get(); - if (false) - Log.v("ddm-heap", "Heap segment enable: when=" + when); - - boolean ok = DdmVmInternal.heapInfoNotify(when); - if (!ok) { - return createFailChunk(1, "Unsupported HPIF what"); - } else { - return null; // empty response - } - } - - /* - * Handle a "HeaP SeGment" or "Native Heap SeGment" request. - */ - private Chunk handleHPSGNHSG(Chunk request, boolean isNative) { - ByteBuffer in = wrapChunk(request); - - int when = in.get(); - int what = in.get(); - if (false) - Log.v("ddm-heap", "Heap segment enable: when=" + when - + ", what=" + what + ", isNative=" + isNative); - - boolean ok = DdmVmInternal.heapSegmentNotify(when, what, isNative); - if (!ok) { - return createFailChunk(1, "Unsupported HPSG what/when"); - } else { - // TODO: if "when" is non-zero and we want to see a dump - // right away, initiate a GC. - return null; // empty response - } - } - - /* - * Handle a "HeaP DUmp" request. - * - * This currently just returns a result code. We could pull up - * the entire contents of the file and return them, but hprof dump - * files can be a few megabytes. - */ - private Chunk handleHPDU(Chunk request) { - ByteBuffer in = wrapChunk(request); - byte result; - - /* get the filename for the output file */ - int len = in.getInt(); - String fileName = getString(in, len); - if (false) - Log.d("ddm-heap", "Heap dump: file='" + fileName + "'"); - - try { - Debug.dumpHprofData(fileName); - result = 0; - } catch (UnsupportedOperationException uoe) { - Log.w("ddm-heap", "hprof dumps not supported in this VM"); - result = -1; - } catch (IOException ioe) { - result = -1; - } catch (RuntimeException re) { - result = -1; - } - - /* create a non-empty reply so the handler fires on completion */ - byte[] reply = { result }; - return new Chunk(CHUNK_HPDU, reply, 0, reply.length); - } - - /* - * Handle a "HeaP Dump Streaming" request. - * - * This tells the VM to create a heap dump and send it directly to - * DDMS. The dumps are large enough that we don't want to copy the - * data into a byte[] and send it from here. - */ - private Chunk handleHPDS(Chunk request) { - ByteBuffer in = wrapChunk(request); - byte result; - - /* get the filename for the output file */ - if (false) - Log.d("ddm-heap", "Heap dump: [DDMS]"); - - String failMsg = null; - try { - Debug.dumpHprofDataDdms(); - } catch (UnsupportedOperationException uoe) { - failMsg = "hprof dumps not supported in this VM"; - } catch (RuntimeException re) { - failMsg = "Exception: " + re.getMessage(); - } - - if (failMsg != null) { - Log.w("ddm-heap", failMsg); - return createFailChunk(1, failMsg); - } else { - return null; - } - } - - /* * Handle a "HeaP Garbage Collection" request. */ private Chunk handleHPGC(Chunk request) { @@ -223,47 +85,4 @@ public class DdmHandleHeap extends ChunkHandler { return null; // empty response } - - /* - * Handle a "REcent Allocation Enable" request. - */ - private Chunk handleREAE(Chunk request) { - ByteBuffer in = wrapChunk(request); - boolean enable; - - enable = (in.get() != 0); - - if (false) - Log.d("ddm-heap", "Recent allocation enable request: " + enable); - - DdmVmInternal.enableRecentAllocations(enable); - - return null; // empty response - } - - /* - * Handle a "REcent Allocation Query" request. - */ - private Chunk handleREAQ(Chunk request) { - //ByteBuffer in = wrapChunk(request); - - byte[] reply = new byte[1]; - reply[0] = DdmVmInternal.getRecentAllocationStatus() ? (byte)1 :(byte)0; - return new Chunk(CHUNK_REAQ, reply, 0, reply.length); - } - - /* - * Handle a "REcent ALlocations" request. - */ - private Chunk handleREAL(Chunk request) { - //ByteBuffer in = wrapChunk(request); - - if (false) - Log.d("ddm-heap", "Recent allocations request"); - - /* generate the reply in a ready-to-go format */ - byte[] reply = DdmVmInternal.getRecentAllocations(); - return new Chunk(CHUNK_REAL, reply, 0, reply.length); - } } - diff --git a/core/java/android/ddm/DdmHandleThread.java b/core/java/android/ddm/DdmHandleThread.java deleted file mode 100644 index 613ab75f9c1b..000000000000 --- a/core/java/android/ddm/DdmHandleThread.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2007 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.ddm; - -import org.apache.harmony.dalvik.ddmc.Chunk; -import org.apache.harmony.dalvik.ddmc.ChunkHandler; -import org.apache.harmony.dalvik.ddmc.DdmServer; -import org.apache.harmony.dalvik.ddmc.DdmVmInternal; -import android.util.Log; -import java.nio.ByteBuffer; - -/** - * Handle thread-related traffic. - */ -public class DdmHandleThread extends ChunkHandler { - - public static final int CHUNK_THEN = type("THEN"); - public static final int CHUNK_THCR = type("THCR"); - public static final int CHUNK_THDE = type("THDE"); - public static final int CHUNK_THST = type("THST"); - public static final int CHUNK_STKL = type("STKL"); - - private static DdmHandleThread mInstance = new DdmHandleThread(); - - - /* singleton, do not instantiate */ - private DdmHandleThread() {} - - /** - * Register for the messages we're interested in. - */ - public static void register() { - DdmServer.registerHandler(CHUNK_THEN, mInstance); - DdmServer.registerHandler(CHUNK_THST, mInstance); - DdmServer.registerHandler(CHUNK_STKL, mInstance); - } - - /** - * Called when the DDM server connects. The handler is allowed to - * send messages to the server. - */ - public void connected() {} - - /** - * Called when the DDM server disconnects. Can be used to disable - * periodic transmissions or clean up saved state. - */ - public void disconnected() {} - - /** - * Handle a chunk of data. - */ - public Chunk handleChunk(Chunk request) { - if (false) - Log.v("ddm-thread", "Handling " + name(request.type) + " chunk"); - int type = request.type; - - if (type == CHUNK_THEN) { - return handleTHEN(request); - } else if (type == CHUNK_THST) { - return handleTHST(request); - } else if (type == CHUNK_STKL) { - return handleSTKL(request); - } else { - throw new RuntimeException("Unknown packet " - + ChunkHandler.name(type)); - } - } - - /* - * Handle a "THread notification ENable" request. - */ - private Chunk handleTHEN(Chunk request) { - ByteBuffer in = wrapChunk(request); - - boolean enable = (in.get() != 0); - //Log.i("ddm-thread", "Thread notify enable: " + enable); - - DdmVmInternal.threadNotify(enable); - return null; // empty response - } - - /* - * Handle a "THread STatus" request. This is constructed by the VM. - */ - private Chunk handleTHST(Chunk request) { - ByteBuffer in = wrapChunk(request); - // currently nothing to read from "in" - - //Log.d("ddm-thread", "Thread status request"); - - byte[] status = DdmVmInternal.getThreadStats(); - if (status != null) - return new Chunk(CHUNK_THST, status, 0, status.length); - else - return createFailChunk(1, "Can't build THST chunk"); - } - - /* - * Handle a STacK List request. - * - * This is done by threadId, which isn't great since those are - * recycled. We need a thread serial ID. The Linux tid is an okay - * answer as it's unlikely to recycle at the exact wrong moment. - * However, we're using the short threadId in THST messages, so we - * use them here for consistency. (One thought is to keep the current - * thread ID in the low 16 bits and somehow serialize the top 16 bits.) - */ - private Chunk handleSTKL(Chunk request) { - ByteBuffer in = wrapChunk(request); - int threadId; - - threadId = in.getInt(); - - //Log.d("ddm-thread", "Stack list request " + threadId); - - StackTraceElement[] trace = DdmVmInternal.getStackTraceById(threadId); - if (trace == null) { - return createFailChunk(1, "Stack trace unavailable"); - } else { - return createStackChunk(trace, threadId); - } - } - - /* - * Serialize a StackTraceElement[] into an STKL chunk. - * - * We include the threadId in the response so the other side doesn't have - * to match up requests and responses as carefully. - */ - private Chunk createStackChunk(StackTraceElement[] trace, int threadId) { - int bufferSize = 0; - - bufferSize += 4; // version, flags, whatever - bufferSize += 4; // thread ID - bufferSize += 4; // frame count - for (StackTraceElement elem : trace) { - bufferSize += 4 + elem.getClassName().length() * 2; - bufferSize += 4 + elem.getMethodName().length() * 2; - bufferSize += 4; - if (elem.getFileName() != null) - bufferSize += elem.getFileName().length() * 2; - bufferSize += 4; // line number - } - - ByteBuffer out = ByteBuffer.allocate(bufferSize); - out.putInt(0); - out.putInt(threadId); - out.putInt(trace.length); - for (StackTraceElement elem : trace) { - out.putInt(elem.getClassName().length()); - putString(out, elem.getClassName()); - out.putInt(elem.getMethodName().length()); - putString(out, elem.getMethodName()); - if (elem.getFileName() != null) { - out.putInt(elem.getFileName().length()); - putString(out, elem.getFileName()); - } else { - out.putInt(0); - } - out.putInt(elem.getLineNumber()); - } - - return new Chunk(CHUNK_STKL, out); - } -} - diff --git a/core/java/android/ddm/DdmRegister.java b/core/java/android/ddm/DdmRegister.java index e0faa51a938e..ca1031287e3e 100644 --- a/core/java/android/ddm/DdmRegister.java +++ b/core/java/android/ddm/DdmRegister.java @@ -16,9 +16,10 @@ package android.ddm; -import org.apache.harmony.dalvik.ddmc.DdmServer; import android.util.Log; +import org.apache.harmony.dalvik.ddmc.DdmServer; + /** * Just a place to stick handler registrations, instead of scattering * them around. @@ -46,7 +47,6 @@ public class DdmRegister { if (false) Log.v("ddm", "Registering DDM message handlers"); DdmHandleHello.register(); - DdmHandleThread.register(); DdmHandleHeap.register(); DdmHandleNativeHeap.register(); DdmHandleProfiling.register(); diff --git a/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java b/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java index 25758e9d9a61..8c7695ad5a5a 100644 --- a/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java +++ b/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java @@ -72,6 +72,45 @@ public final class FontFamilyUpdateRequest { * A font family definition. */ public static final class FontFamily { + + /** + * Builds a {@link FontFamily}. + */ + public static final class Builder { + @NonNull private final String mName; + @NonNull private final List<Font> mFonts; + + /** + * Constructs a {@link FontFamily.Builder}. + */ + public Builder(@NonNull String name, @NonNull List<Font> fonts) { + Objects.requireNonNull(name); + Preconditions.checkStringNotEmpty(name); + Objects.requireNonNull(fonts); + Preconditions.checkCollectionElementsNotNull(fonts, "fonts"); + Preconditions.checkCollectionNotEmpty(fonts, "fonts"); + mName = name; + mFonts = new ArrayList<>(fonts); + } + + /** + * Adds a {@link Font} to the builder. + * + * @return This builder object. + */ + public @NonNull Builder addFont(@NonNull Font font) { + mFonts.add(font); + return this; + } + + /** + * Builds a {@link FontFamily}. + */ + public @NonNull FontFamily build() { + return new FontFamily(mName, mFonts); + } + } + @NonNull private final String mName; @NonNull @@ -90,12 +129,7 @@ public final class FontFamilyUpdateRequest { * @see android.graphics.Typeface#create(String, int) * @see Font */ - public FontFamily(@NonNull String name, @NonNull List<Font> fonts) { - Objects.requireNonNull(name); - Preconditions.checkStringNotEmpty(name); - Objects.requireNonNull(fonts); - Preconditions.checkCollectionElementsNotNull(fonts, "fonts"); - Preconditions.checkCollectionNotEmpty(fonts, "fonts"); + private FontFamily(@NonNull String name, @NonNull List<Font> fonts) { mName = name; mFonts = fonts; } diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java index 7bf692f1d318..fa2ccbc189ad 100644 --- a/core/java/android/graphics/fonts/FontManager.java +++ b/core/java/android/graphics/fonts/FontManager.java @@ -195,6 +195,7 @@ public class FontManager { * @return The current font configuration. null if failed to fetch information from the system * service. */ + @RequiresPermission(Manifest.permission.UPDATE_FONTS) public @NonNull FontConfig getFontConfig() { try { return mIFontManager.getFontConfig(); diff --git a/core/java/android/hardware/SensorPrivacyManagerInternal.java b/core/java/android/hardware/SensorPrivacyManagerInternal.java new file mode 100644 index 000000000000..d12e9f8418bc --- /dev/null +++ b/core/java/android/hardware/SensorPrivacyManagerInternal.java @@ -0,0 +1,64 @@ +/* + * 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; + +/** + * SensorPrivacyManager calls for within the system server + * @hide + */ +public abstract class SensorPrivacyManagerInternal { + + /** + * A class implementing this interface can register to receive a callback when state changes. + */ + public interface OnSensorPrivacyChangedListener { + /** + * The callback invoked when the state changes. + */ + void onSensorPrivacyChanged(boolean enabled); + } + + /** + * A class implementing this interface can register to receive a callback when state changes for + * any user. + */ + public interface OnUserSensorPrivacyChangedListener { + /** + * The callback invoked when the state changes. + */ + void onSensorPrivacyChanged(int userId, boolean enabled); + } + + /** + * Get the individual sensor privacy state for a given user. + */ + public abstract boolean isSensorPrivacyEnabled(int userId, int sensor); + + /** + * Registers a new listener to receive notification when the state of sensor privacy + * changes. + */ + public abstract void addSensorPrivacyListener(int userId, int sensor, + OnSensorPrivacyChangedListener listener); + + /** + * Registers a new listener to receive notification when the state of sensor privacy + * changes for any user. + */ + public abstract void addSensorPrivacyListenerForAllUsers(int sensor, + OnUserSensorPrivacyChangedListener listener); +} diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java index 788afe3bdb8e..365dea691489 100644 --- a/core/java/android/hardware/SystemSensorManager.java +++ b/core/java/android/hardware/SystemSensorManager.java @@ -65,7 +65,7 @@ public class SystemSensorManager extends SensorManager { private static final int CAPPED_SAMPLING_RATE_LEVEL = SensorDirectChannel.RATE_NORMAL; private static final String HIGH_SAMPLING_RATE_SENSORS_PERMISSION = - "android.permisison.HIGH_SAMPLING_RATE_SENSORS"; + "android.permission.HIGH_SAMPLING_RATE_SENSORS"; /** * For apps targeting S and above, a SecurityException is thrown when they do not have * HIGH_SAMPLING_RATE_SENSORS permission, run in debug mode, and request sampling rates that diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java index 7dc1eaabdc9c..93e5a0ea18f3 100644 --- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java +++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java @@ -52,7 +52,8 @@ public class AmbientDisplayConfiguration { || wakeDisplayGestureEnabled(user) || pickupGestureEnabled(user) || tapGestureEnabled(user) - || doubleTapGestureEnabled(user); + || doubleTapGestureEnabled(user) + || quickPickupSensorEnabled(user); } /** {@hide} */ @@ -100,6 +101,13 @@ public class AmbientDisplayConfiguration { } /** {@hide} */ + public boolean quickPickupSensorEnabled(int user) { + return boolSettingDefaultOff(Settings.Secure.DOZE_QUICK_PICKUP_GESTURE, user) + && !TextUtils.isEmpty(quickPickupSensorType()) + && !alwaysOnEnabled(user); + } + + /** {@hide} */ public boolean wakeScreenGestureAvailable() { return mContext.getResources() .getBoolean(R.bool.config_dozeWakeLockScreenSensorAvailable); @@ -143,6 +151,11 @@ public class AmbientDisplayConfiguration { } /** {@hide} */ + public String quickPickupSensorType() { + return mContext.getResources().getString(R.string.config_quickPickupSensorType); + } + + /** {@hide} */ public boolean pulseOnLongPressEnabled(int user) { return pulseOnLongPressAvailable() && boolSettingDefaultOff( Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, user); diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index bbf421da6b48..2c3e7f18a3ab 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -68,6 +68,9 @@ public final class DisplayManager { * {@link #EXTRA_WIFI_DISPLAY_STATUS} extra. * </p><p> * This broadcast is only sent to registered receivers and can only be sent by the system. + * </p><p> + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission is required to + * receive this broadcast. * </p> * @hide */ diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 0256b7bc6de0..8dc8d5b60943 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -475,28 +475,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * @hide */ @RequiresPermission(MANAGE_BIOMETRIC) - public void revokeChallenge() { - final List<FaceSensorPropertiesInternal> faceSensorProperties = - getSensorPropertiesInternal(); - if (faceSensorProperties.isEmpty()) { - Slog.e(TAG, "No sensors during revokeChallenge"); - } - revokeChallenge(faceSensorProperties.get(0).sensorId); - } - - /** - * Invalidates the current challenge. - * - * TODO(b/171335732): should take userId and challenge - * - * @hide - */ - @RequiresPermission(MANAGE_BIOMETRIC) - public void revokeChallenge(int sensorId) { + public void revokeChallenge(int sensorId, int userId, long challenge) { if (mService != null) { try { - mService.revokeChallenge(mToken, sensorId, 0 /* userId */, - mContext.getOpPackageName(), 0 /* challenge */); + mService.revokeChallenge(mToken, sensorId, userId, + mContext.getOpPackageName(), challenge); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index fc795d8a0488..1c33b26dfa18 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -686,17 +686,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } /** - * Revokes the current challenge. - * @hide - */ - @RequiresPermission(MANAGE_FINGERPRINT) - public void revokeChallenge(int userId) { - // On HALs with only single in-flight challenge such as IBiometricsFingerprint@2.1, - // this parameter is ignored. - revokeChallenge(userId, 0L); - } - - /** * Revokes the specified challenge. * @hide */ diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index b90c72832d36..ad71f15f6e26 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -461,6 +461,7 @@ public final class HdmiControlManager { * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE * @hide */ + @SystemApi public static final int VOLUME_CONTROL_ENABLED = 1; /** * HDMI CEC disabled. @@ -468,6 +469,7 @@ public final class HdmiControlManager { * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE * @hide */ + @SystemApi public static final int VOLUME_CONTROL_DISABLED = 0; /** * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE @@ -486,12 +488,14 @@ public final class HdmiControlManager { * * @hide */ + @SystemApi public static final int TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED = 1; /** * TV Wake on One Touch Play disabled. * * @hide */ + @SystemApi public static final int TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED = 0; /** * @hide @@ -509,12 +513,14 @@ public final class HdmiControlManager { * * @hide */ + @SystemApi public static final int TV_SEND_STANDBY_ON_SLEEP_ENABLED = 1; /** * Not sending <Standby> on sleep. * * @hide */ + @SystemApi public static final int TV_SEND_STANDBY_ON_SLEEP_DISABLED = 0; /** * @hide @@ -759,6 +765,7 @@ public final class HdmiControlManager { * @hide * @see android.hardware.hdmi.HdmiControlManager#setHdmiCecVolumeControlEnabled(int) */ + @SystemApi public static final String CEC_SETTING_NAME_VOLUME_CONTROL_MODE = "volume_control_enabled"; /** @@ -767,6 +774,7 @@ public final class HdmiControlManager { * * @hide */ + @SystemApi public static final String CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY = "tv_wake_on_one_touch_play"; /** @@ -775,6 +783,7 @@ public final class HdmiControlManager { * * @hide */ + @SystemApi public static final String CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP = "tv_send_standby_on_sleep"; /** @@ -1259,6 +1268,7 @@ public final class HdmiControlManager { * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecVolumeControlEnabled( @VolumeControl int hdmiCecVolumeControlEnabled) { @@ -1274,6 +1284,7 @@ public final class HdmiControlManager { * Returns whether volume changes via HDMI CEC are enabled. * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.HDMI_CEC) @VolumeControl public int getHdmiCecVolumeControlEnabled() { @@ -2155,6 +2166,7 @@ public final class HdmiControlManager { * * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setTvWakeOnOneTouchPlay(@NonNull @TvWakeOnOneTouchPlay int value) { if (mService == null) { @@ -2176,6 +2188,7 @@ public final class HdmiControlManager { * * @hide */ + @SystemApi @NonNull @TvWakeOnOneTouchPlay @RequiresPermission(android.Manifest.permission.HDMI_CEC) @@ -2199,6 +2212,7 @@ public final class HdmiControlManager { * * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setTvSendStandbyOnSleep(@NonNull @TvSendStandbyOnSleep int value) { if (mService == null) { @@ -2220,6 +2234,7 @@ public final class HdmiControlManager { * * @hide */ + @SystemApi @NonNull @TvSendStandbyOnSleep @RequiresPermission(android.Manifest.permission.HDMI_CEC) diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index a65f36b14f13..eaa8bd403e24 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -60,7 +60,8 @@ public final class ContextHubManager { private static final String TAG = "ContextHubManager"; /** - * An extra of type int describing the client's authorization state. + * An extra containing an int from {@link AuthorizationState} describing the client's + * authorization state. */ public static final String EXTRA_CLIENT_AUTHORIZATION_STATE = "android.hardware.location.extra.CLIENT_AUTHORIZATION_STATE"; @@ -115,11 +116,9 @@ public final class ContextHubManager { /** * Indicates the {@link ContextHubClient} will soon lose its authorization to communicate with a - * nanoapp. The {@link ContextHubClient} must perform any cleanup with the nanoapp as soon as - * possible. - * - * Note that the time between this state event and {@link AUTHORIZATION_DENIED} must be enough - * for the {@link ContextHubClient} to send at least one message to the nanoapp. + * nanoapp. After receiving this state event, the {@link ContextHubClient} has one minute to + * perform any cleanup with the nanoapp such that the nanoapp is no longer performing work on + * behalf of the {@link ContextHubClient}. */ public static final int AUTHORIZATION_DENIED_GRACE_PERIOD = 1; diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index 5cfcd667632b..9198eb74d1f8 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -171,7 +171,7 @@ class IInputMethodWrapper extends IInputMethod.Stub SomeArgs args = (SomeArgs) msg.obj; try { inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1, - (IInputMethodPrivilegedOperations) args.arg2); + (IInputMethodPrivilegedOperations) args.arg2, (int) args.arg3); } finally { args.recycle(); } @@ -280,9 +280,10 @@ class IInputMethodWrapper extends IInputMethod.Stub @BinderThread @Override public void initializeInternal(IBinder token, int displayId, - IInputMethodPrivilegedOperations privOps) { + IInputMethodPrivilegedOperations privOps, int configChanges) { mCaller.executeOrSendMessage( - mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps)); + mCaller.obtainMessageIOOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps, + configChanges)); } @BinderThread diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 7e2be01feb01..40a0fc4e8339 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -70,6 +70,7 @@ import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; @@ -131,6 +132,7 @@ import android.widget.TextView; import android.window.WindowMetricsHelper; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperations; @@ -513,6 +515,8 @@ public class InputMethodService extends AbstractInputMethodService { private boolean mIsAutomotive; private Handler mHandler; private boolean mImeSurfaceScheduledForRemoval; + private Configuration mLastKnownConfig; + private int mHandledConfigChanges; /** * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput} @@ -588,12 +592,13 @@ public class InputMethodService extends AbstractInputMethodService { @MainThread @Override public final void initializeInternal(@NonNull IBinder token, int displayId, - IInputMethodPrivilegedOperations privilegedOperations) { + IInputMethodPrivilegedOperations privilegedOperations, int configChanges) { if (InputMethodPrivilegedOperationsRegistry.isRegistered(token)) { Log.w(TAG, "The token has already registered, ignore this initialization."); return; } Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal"); + mHandledConfigChanges = configChanges; mPrivOps.set(privilegedOperations); InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps); updateInputMethodDisplay(displayId); @@ -821,6 +826,9 @@ public class InputMethodService extends AbstractInputMethodService { setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition); } final boolean isVisible = isInputViewShown(); + if (isVisible && getResources() != null) { + mLastKnownConfig = new Configuration(getResources().getConfiguration()); + } final boolean visibilityChanged = isVisible != wasVisible; if (resultReceiver != null) { resultReceiver.send(visibilityChanged @@ -1428,10 +1436,30 @@ public class InputMethodService extends AbstractInputMethodService { * state: {@link #onStartInput} if input is active, and * {@link #onCreateInputView} and {@link #onStartInputView} and related * appropriate functions if the UI is displayed. + * <p>Starting with {@link Build.VERSION_CODES#S}, IMEs can opt into handling configuration + * changes themselves instead of being restarted with + * {@link android.R.styleable#InputMethod_configChanges}. */ @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - resetStateForNewConfiguration(); + if (shouldImeRestartForConfig(newConfig)) { + resetStateForNewConfiguration(); + } + } + + /** + * @return {@code true} if {@link InputMethodService} needs to restart to handle + * .{@link #onConfigurationChanged(Configuration)} + */ + @VisibleForTesting + boolean shouldImeRestartForConfig(@NonNull Configuration newConfig) { + if (mLastKnownConfig == null) { + return true; + } + // If the new config is the same as the config this Service is already running with, + // then don't bother calling resetStateForNewConfiguration. + int unhandledDiff = (mLastKnownConfig.diffPublicOnly(newConfig) & ~mHandledConfigChanges); + return unhandledDiff != 0; } private void resetStateForNewConfiguration() { @@ -3181,7 +3209,17 @@ public class InputMethodService extends AbstractInputMethodService { requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS); } } - + + @VisibleForTesting + void setLastKnownConfig(@NonNull Configuration config) { + mLastKnownConfig = config; + } + + @VisibleForTesting + void setHandledConfigChanges(int configChanges) { + mHandledConfigChanges = configChanges; + } + void startExtractingText(boolean inputChanged) { final ExtractEditText eet = mExtractEditText; if (eet != null && getCurrentInputStarted() diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java index f472ed4381d1..77754d1256a7 100644 --- a/core/java/android/net/VpnManager.java +++ b/core/java/android/net/VpnManager.java @@ -16,12 +16,15 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.UserIdInt; import android.app.Activity; import android.content.ComponentName; @@ -56,18 +59,21 @@ import java.util.List; */ public class VpnManager { /** Type representing a lack of VPN @hide */ + @SystemApi(client = MODULE_LIBRARIES) public static final int TYPE_VPN_NONE = -1; /** * A VPN created by an app using the {@link VpnService} API. * @hide */ + @SystemApi(client = MODULE_LIBRARIES) public static final int TYPE_VPN_SERVICE = 1; /** * A VPN created using a {@link VpnManager} API such as {@link #startProvisionedVpnProfile}. * @hide */ + @SystemApi(client = MODULE_LIBRARIES) public static final int TYPE_VPN_PLATFORM = 2; /** @@ -76,6 +82,7 @@ public class VpnManager { * @hide */ @Deprecated + @SystemApi(client = MODULE_LIBRARIES) public static final int TYPE_VPN_LEGACY = 3; /** diff --git a/core/java/android/os/BatteryManagerInternal.java b/core/java/android/os/BatteryManagerInternal.java index a86237dd271f..97ec5940ccb0 100644 --- a/core/java/android/os/BatteryManagerInternal.java +++ b/core/java/android/os/BatteryManagerInternal.java @@ -83,4 +83,29 @@ public abstract class BatteryManagerInternal { * wait on the battery service lock. */ public abstract int getInvalidCharger(); + + /** + * Sets battery AC charger to enabled/disabled, and freezes the battery state. + */ + public abstract void setChargerAcOnline(boolean online, boolean forceUpdate); + + /** + * Sets battery level, and freezes the battery state. + */ + public abstract void setBatteryLevel(int level, boolean forceUpdate); + + /** + * Unplugs battery, and freezes the battery state. + */ + public abstract void unplugBattery(boolean forceUpdate); + + /** + * Unfreezes battery state, returning to current hardware values. + */ + public abstract void resetBattery(boolean forceUpdate); + + /** + * Suspend charging even if plugged in. + */ + public abstract void suspendBatteryInput(); } diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java index 1905d708d6d3..e47478abf439 100644 --- a/core/java/android/os/BatteryStatsManager.java +++ b/core/java/android/os/BatteryStatsManager.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.content.Context; import android.net.NetworkStack; import android.os.connectivity.CellularBatteryStats; @@ -487,4 +488,74 @@ public final class BatteryStatsManager { return isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; } -} + + /** + * Sets battery AC charger to enabled/disabled, and freezes the battery state. + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + public void setChargerAcOnline(boolean online, boolean forceUpdate) { + try { + mBatteryStats.setChargerAcOnline(online, forceUpdate); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Sets battery level, and freezes the battery state. + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + public void setBatteryLevel(int level, boolean forceUpdate) { + try { + mBatteryStats.setBatteryLevel(level, forceUpdate); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Unplugs battery, and freezes the battery state. + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + public void unplugBattery(boolean forceUpdate) { + try { + mBatteryStats.unplugBattery(forceUpdate); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Unfreezes battery state, returning to current hardware values. + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + public void resetBattery(boolean forceUpdate) { + try { + mBatteryStats.resetBattery(forceUpdate); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Suspend charging even if plugged in. + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.DEVICE_POWER) + public void suspendBatteryInput() { + try { + mBatteryStats.suspendBatteryInput(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } +}
\ No newline at end of file diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 83f78a56487a..0d9f715c11d4 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -27,6 +27,7 @@ import android.app.ActivityThread; import android.app.Application; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.sysprop.DeviceProperties; import android.sysprop.SocProperties; import android.sysprop.TelephonyProperties; import android.text.TextUtils; @@ -298,6 +299,19 @@ public class Build { "ro.build.version.security_patch", ""); /** + * The media performance class of the device or 0 if none. + * <p> + * If this value is not <code>0</code>, the device conforms to the media performance class + * definition of the SDK version of this value. This value never changes while a device is + * booted, but it may increase when the hardware manufacturer provides an OTA update. + * <p> + * Possible non-zero values are defined in {@link Build.VERSION_CODES} starting with + * {@link Build.VERSION_CODES#S}. + */ + public static final int MEDIA_PERFORMANCE_CLASS = + DeviceProperties.media_performance_class().orElse(0); + + /** * The user-visible SDK version of the framework in its raw String * representation; use {@link #SDK_INT} instead. * diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 124c0b00b2b2..21bf8b8c30e4 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -728,11 +728,11 @@ public class Environment { /** * Standard directory in which to place any audio files that should be * in the regular list of music for the user. - * This may be combined with + * This may be combined with {@link #DIRECTORY_AUDIOBOOKS}, * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, - * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series - * of directories to categories a particular audio file as more than one - * type. + * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and + * {@link #DIRECTORY_RECORDINGS} as a series of directories to + * categorize a particular audio file as more than one type. */ public static String DIRECTORY_MUSIC = "Music"; @@ -741,10 +741,10 @@ public class Environment { * in the list of podcasts that the user can select (not as regular * music). * This may be combined with {@link #DIRECTORY_MUSIC}, - * {@link #DIRECTORY_NOTIFICATIONS}, - * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series - * of directories to categories a particular audio file as more than one - * type. + * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_NOTIFICATIONS}, + * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and + * {@link #DIRECTORY_RECORDINGS} as a series of directories to + * categorize a particular audio file as more than one type. */ public static String DIRECTORY_PODCASTS = "Podcasts"; @@ -753,10 +753,10 @@ public class Environment { * in the list of ringtones that the user can select (not as regular * music). * This may be combined with {@link #DIRECTORY_MUSIC}, - * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and - * {@link #DIRECTORY_ALARMS} as a series - * of directories to categories a particular audio file as more than one - * type. + * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS}, + * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS}, + * and {@link #DIRECTORY_RECORDINGS} as a series of directories + * to categorize a particular audio file as more than one type. */ public static String DIRECTORY_RINGTONES = "Ringtones"; @@ -765,10 +765,10 @@ public class Environment { * in the list of alarms that the user can select (not as regular * music). * This may be combined with {@link #DIRECTORY_MUSIC}, - * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, - * and {@link #DIRECTORY_RINGTONES} as a series - * of directories to categories a particular audio file as more than one - * type. + * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS}, + * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_RINGTONES}, + * and {@link #DIRECTORY_RECORDINGS} as a series of directories + * to categorize a particular audio file as more than one type. */ public static String DIRECTORY_ALARMS = "Alarms"; @@ -777,10 +777,10 @@ public class Environment { * in the list of notifications that the user can select (not as regular * music). * This may be combined with {@link #DIRECTORY_MUSIC}, - * {@link #DIRECTORY_PODCASTS}, - * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series - * of directories to categories a particular audio file as more than one - * type. + * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS}, + * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and + * {@link #DIRECTORY_RECORDINGS} as a series of directories to + * categorize a particular audio file as more than one type. */ public static String DIRECTORY_NOTIFICATIONS = "Notifications"; @@ -831,14 +831,26 @@ public class Environment { public static String DIRECTORY_SCREENSHOTS = "Screenshots"; /** - * Standard directory in which to place any audio files which are - * audiobooks. + * Standard directory in which to place any audio files that should be + * in the list of audiobooks that the user can select (not as regular + * music). + * This may be combined with {@link #DIRECTORY_MUSIC}, + * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, + * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, + * and {@link #DIRECTORY_RECORDINGS} as a series of directories + * to categorize a particular audio file as more than one type. */ public static String DIRECTORY_AUDIOBOOKS = "Audiobooks"; /** - * Standard directory in which to place any audio files which are - * recordings. + * Standard directory in which to place any audio files that should be + * in the list of voice recordings recorded by voice recorder apps that + * the user can select (not as regular music). + * This may be combined with {@link #DIRECTORY_MUSIC}, + * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS}, + * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS}, + * and {@link #DIRECTORY_RINGTONES} as a series of directories + * to categorize a particular audio file as more than one type. */ @NonNull // The better way is that expose a static method getRecordingDirectories. diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index a46af9754f32..b12dad038ce3 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -1247,9 +1247,9 @@ public final class FileUtils { } /** - * Creates a directory with name {@code name} under an existing directory {@code baseDir}. - * Returns a {@code File} object representing the directory on success, {@code null} on - * failure. + * Creates a directory with name {@code name} under an existing directory {@code baseDir} if it + * doesn't exist already. Returns a {@code File} object representing the directory if it exists + * and {@code null} if not. * * @hide */ @@ -1259,13 +1259,23 @@ public final class FileUtils { return createDir(dir) ? dir : null; } - /** @hide */ + /** + * Ensure the given directory exists, creating it if needed. This method is threadsafe. + * + * @return false if the directory doesn't exist and couldn't be created + * + * @hide + */ public static boolean createDir(File dir) { + if (dir.mkdir()) { + return true; + } + if (dir.exists()) { return dir.isDirectory(); } - return dir.mkdir(); + return false; } /** diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 786a7d08047e..a19728c5c498 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -323,6 +323,13 @@ public final class PowerManager { public static final int USER_ACTIVITY_EVENT_ATTENTION = 4; /** + * User activity event type: {@link com.android.server.power.FaceDownDetector} taking action + * on behalf of user. + * @hide + */ + public static final int USER_ACTIVITY_EVENT_FACE_DOWN = 5; + + /** * User activity flag: If already dimmed, extend the dim timeout * but do not brighten. This flag is useful for keeping the screen on * a little longer without causing a visible change such as when diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java index 73520e07d118..2a42b981ac26 100644 --- a/core/java/android/os/incremental/IncrementalFileStorages.java +++ b/core/java/android/os/incremental/IncrementalFileStorages.java @@ -51,6 +51,8 @@ import java.util.UUID; public final class IncrementalFileStorages { private static final String TAG = "IncrementalFileStorages"; + private static final String SYSTEM_DATA_LOADER_PACKAGE = "android"; + private @NonNull final IncrementalManager mIncrementalManager; private @NonNull final File mStageDir; private @Nullable IncrementalStorage mInheritedStorage; @@ -116,7 +118,10 @@ public final class IncrementalFileStorages { mInheritedStorage = mIncrementalManager.openStorage( inheritedDir.getAbsolutePath()); if (mInheritedStorage != null) { - if (!mInheritedStorage.isFullyLoaded()) { + boolean systemDataLoader = SYSTEM_DATA_LOADER_PACKAGE.equals( + dataLoaderParams.getComponentName().getPackageName()); + if (systemDataLoader && !mInheritedStorage.isFullyLoaded()) { + // System data loader does not support incomplete storages. throw new IOException("Inherited storage has missing pages."); } diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java index dc6f63a94685..047c05a8734b 100644 --- a/core/java/android/os/incremental/IncrementalManager.java +++ b/core/java/android/os/incremental/IncrementalManager.java @@ -30,6 +30,7 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -265,6 +266,13 @@ public final class IncrementalManager { } /** + * Checks if an fd corresponds to a file on a mounted Incremental File System. + */ + public static boolean isIncrementalFileFd(@NonNull FileDescriptor fd) { + return nativeIsIncrementalFd(fd.getInt$()); + } + + /** * Returns raw signature for file if it's on Incremental File System. * Unsafe, use only if you are sure what you are doing. */ @@ -421,9 +429,22 @@ public final class IncrementalManager { storage.unregisterStorageHealthListener(); } + /** + * Returns the metrics of an Incremental Storage. + */ + public IncrementalMetrics getMetrics(@NonNull String codePath) { + final IncrementalStorage storage = openStorage(codePath); + if (storage == null) { + // storage does not exist, package not installed + return null; + } + return new IncrementalMetrics(storage.getMetrics()); + } + /* Native methods */ private static native boolean nativeIsEnabled(); private static native boolean nativeIsV2Available(); private static native boolean nativeIsIncrementalPath(@NonNull String path); + private static native boolean nativeIsIncrementalFd(@NonNull int fd); private static native byte[] nativeUnsafeGetFileSignature(@NonNull String path); } diff --git a/core/java/android/os/incremental/IncrementalMetrics.java b/core/java/android/os/incremental/IncrementalMetrics.java new file mode 100644 index 000000000000..44dea1be50f0 --- /dev/null +++ b/core/java/android/os/incremental/IncrementalMetrics.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.incremental; + +import android.annotation.NonNull; +import android.os.PersistableBundle; + +/** + * Provides methods to access metrics about an app installed via Incremental + * @hide + */ +public class IncrementalMetrics { + @NonNull private final PersistableBundle mData; + + public IncrementalMetrics(@NonNull PersistableBundle data) { + mData = data; + } + + /** + * @return Milliseconds between now and when the oldest pending read happened + */ + public long getMillisSinceOldestPendingRead() { + return mData.getLong(IIncrementalService.METRICS_MILLIS_SINCE_OLDEST_PENDING_READ, -1); + } +} diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java index e6ce8cd56d28..7cf0144d71f7 100644 --- a/core/java/android/os/incremental/IncrementalStorage.java +++ b/core/java/android/os/incremental/IncrementalStorage.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.DataLoaderParams; import android.content.pm.IDataLoaderStatusListener; +import android.os.PersistableBundle; import android.os.RemoteException; import java.io.File; @@ -601,4 +602,17 @@ public final class IncrementalStorage { return; } } + + /** + * Returns the metrics of the current storage. + * {@see IIncrementalService} for metrics keys. + */ + public PersistableBundle getMetrics() { + try { + return mService.getMetrics(mId); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + return null; + } + } } diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index 396ba2d3cea5..82c4c715f4b0 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -52,6 +52,11 @@ public abstract class StorageManagerInternal { } /** + * Return true if fuse is mounted. + */ + public abstract boolean isFuseMounted(int userId); + + /** * Create storage directories if it does not exist. * Return true if the directories were setup correctly, otherwise false. */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 4dfbb6fa2d05..6865041a5037 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8369,6 +8369,14 @@ public final class Settings { public static final String DOZE_WAKE_DISPLAY_GESTURE = "doze_wake_display_gesture"; /** + * Gesture that wakes up the display on quick pickup, toggling between + * {@link Display.STATE_OFF} and {@link Display.STATE_DOZE}. + * @hide + */ + @Readable + public static final String DOZE_QUICK_PICKUP_GESTURE = "doze_quick_pickup_gesture"; + + /** * Whether the device should suppress the current doze configuration and disable dozing. * @hide */ diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java index 4c8ee598f512..00c30b12c93d 100644 --- a/core/java/android/service/autofill/AutofillServiceInfo.java +++ b/core/java/android/service/autofill/AutofillServiceInfo.java @@ -23,6 +23,7 @@ import android.app.AppGlobals; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; @@ -38,6 +39,7 @@ import android.util.Log; import android.util.Xml; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.XmlUtils; @@ -233,6 +235,39 @@ public final class AutofillServiceInfo { return compatibilityPackages; } + /** + * Used by {@link TestDataBuilder}. + */ + private AutofillServiceInfo(String passwordsActivity) { + mServiceInfo = new ServiceInfo(); + mServiceInfo.applicationInfo = new ApplicationInfo(); + mServiceInfo.packageName = "com.android.test"; + mSettingsActivity = null; + mPasswordsActivity = passwordsActivity; + mCompatibilityPackages = null; + mInlineSuggestionsEnabled = false; + } + + /** + * Builds test data for unit tests. + */ + @VisibleForTesting + public static final class TestDataBuilder { + private String mPasswordsActivity; + + public TestDataBuilder() { + } + + public TestDataBuilder setPasswordsActivity(String passwordsActivity) { + mPasswordsActivity = passwordsActivity; + return this; + } + + public AutofillServiceInfo build() { + return new AutofillServiceInfo(mPasswordsActivity); + } + } + @NonNull public ServiceInfo getServiceInfo() { return mServiceInfo; diff --git a/core/java/android/service/rotationresolver/RotationResolutionRequest.java b/core/java/android/service/rotationresolver/RotationResolutionRequest.java index 8e76e2fc9202..8dec0922b097 100644 --- a/core/java/android/service/rotationresolver/RotationResolutionRequest.java +++ b/core/java/android/service/rotationresolver/RotationResolutionRequest.java @@ -16,12 +16,15 @@ package android.service.rotationresolver; +import android.annotation.DurationMillisLong; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.view.Surface; +import com.android.internal.util.DataClass; + /** * This class represents a request to an {@link RotationResolverService}. The request contains * information from the system that can help RotationResolverService to determine the appropriate @@ -33,68 +36,209 @@ import android.view.Surface; * @hide */ @SystemApi +@DataClass ( + genParcelable = true, + genToString = true +) public final class RotationResolutionRequest implements Parcelable { - private final @NonNull String mPackageName; - private final int mProposedRotation; - private final int mCurrentRotation; - private final long mTimeoutMillis; + /** The Name of the package of the current fore-ground activity. */ + @NonNull private final String mPackageName; + + /** The current rotation of the screen. */ + @Surface.Rotation private final int mCurrentRotation; + + /** The proposed screen rotation in the system. */ + @Surface.Rotation private final int mProposedRotation; + + /** Whether should use camera signal to resolver rotation. */ + private final boolean mShouldUseCamera; + + /** The timeout of the request. */ + @DurationMillisLong private final long mTimeoutMillis; + + + + + // Code below generated by codegen v1.0.22. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/rotationresolver/RotationResolutionRequest.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + /** - * @param proposedRotation The system proposed screen rotation. - * @param currentRotation The current screen rotation of the phone. - * @param packageName The current package name of the activity that is running in - * foreground. - * @param timeoutMillis The timeout in millisecond for the rotation request. - * @hide + * Creates a new RotationResolutionRequest. + * + * @param packageName + * The Name of the package of the current fore-ground activity. + * @param currentRotation + * The current rotation of the screen. + * @param proposedRotation + * The proposed screen rotation in the system. + * @param shouldUseCamera + * Whether should use camera signal to resolver rotation. + * @param timeoutMillis + * The timeout of the request. */ - public RotationResolutionRequest(int proposedRotation, int currentRotation, - @NonNull String packageName, long timeoutMillis) { - mProposedRotation = proposedRotation; - mCurrentRotation = currentRotation; - mPackageName = packageName; - mTimeoutMillis = timeoutMillis; + @DataClass.Generated.Member + public RotationResolutionRequest( + @NonNull String packageName, + @Surface.Rotation int currentRotation, + @Surface.Rotation int proposedRotation, + boolean shouldUseCamera, + @DurationMillisLong long timeoutMillis) { + this.mPackageName = packageName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mPackageName); + this.mCurrentRotation = currentRotation; + com.android.internal.util.AnnotationValidations.validate( + Surface.Rotation.class, null, mCurrentRotation); + this.mProposedRotation = proposedRotation; + com.android.internal.util.AnnotationValidations.validate( + Surface.Rotation.class, null, mProposedRotation); + this.mShouldUseCamera = shouldUseCamera; + this.mTimeoutMillis = timeoutMillis; + com.android.internal.util.AnnotationValidations.validate( + DurationMillisLong.class, null, mTimeoutMillis); + + // onConstructed(); // You can define this method to get a callback } - @Surface.Rotation public int getProposedRotation() { - return mProposedRotation; + /** + * The Name of the package of the current fore-ground activity. + */ + @DataClass.Generated.Member + public @NonNull String getPackageName() { + return mPackageName; } - public int getCurrentRotation() { + /** + * The current rotation of the screen. + */ + @DataClass.Generated.Member + public @Surface.Rotation int getCurrentRotation() { return mCurrentRotation; } - public @NonNull String getPackageName() { - return mPackageName; + /** + * The proposed screen rotation in the system. + */ + @DataClass.Generated.Member + public @Surface.Rotation int getProposedRotation() { + return mProposedRotation; } - public long getTimeoutMillis() { + /** + * Whether should use camera signal to resolver rotation. + */ + @DataClass.Generated.Member + public boolean shouldUseCamera() { + return mShouldUseCamera; + } + + /** + * The timeout of the request. + */ + @DataClass.Generated.Member + public @DurationMillisLong long getTimeoutMillis() { return mTimeoutMillis; } @Override - public int describeContents() { - return 0; + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "RotationResolutionRequest { " + + "packageName = " + mPackageName + ", " + + "currentRotation = " + mCurrentRotation + ", " + + "proposedRotation = " + mProposedRotation + ", " + + "shouldUseCamera = " + mShouldUseCamera + ", " + + "timeoutMillis = " + mTimeoutMillis + + " }"; } @Override - public void writeToParcel(@NonNull Parcel parcel, int flags) { - parcel.writeInt(mProposedRotation); - parcel.writeInt(mCurrentRotation); - parcel.writeString(mPackageName); - parcel.writeLong(mTimeoutMillis); + @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 (mShouldUseCamera) flg |= 0x8; + dest.writeByte(flg); + dest.writeString(mPackageName); + dest.writeInt(mCurrentRotation); + dest.writeInt(mProposedRotation); + dest.writeLong(mTimeoutMillis); } - public static final @NonNull Creator<RotationResolutionRequest> CREATOR = - new Creator<RotationResolutionRequest>() { - @Override - public RotationResolutionRequest createFromParcel(Parcel source) { - return new RotationResolutionRequest(source.readInt(), source.readInt(), - source.readString(), source.readLong()); - } + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ RotationResolutionRequest(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + byte flg = in.readByte(); + boolean shouldUseCamera = (flg & 0x8) != 0; + String packageName = in.readString(); + int currentRotation = in.readInt(); + int proposedRotation = in.readInt(); + long timeoutMillis = in.readLong(); + + this.mPackageName = packageName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mPackageName); + this.mCurrentRotation = currentRotation; + com.android.internal.util.AnnotationValidations.validate( + Surface.Rotation.class, null, mCurrentRotation); + this.mProposedRotation = proposedRotation; + com.android.internal.util.AnnotationValidations.validate( + Surface.Rotation.class, null, mProposedRotation); + this.mShouldUseCamera = shouldUseCamera; + this.mTimeoutMillis = timeoutMillis; + com.android.internal.util.AnnotationValidations.validate( + DurationMillisLong.class, null, mTimeoutMillis); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<RotationResolutionRequest> CREATOR + = new Parcelable.Creator<RotationResolutionRequest>() { @Override public RotationResolutionRequest[] newArray(int size) { return new RotationResolutionRequest[size]; } + + @Override + public RotationResolutionRequest createFromParcel(@NonNull Parcel in) { + return new RotationResolutionRequest(in); + } }; + + @DataClass.Generated( + time = 1615402421314L, + codegenVersion = "1.0.22", + sourceFile = "frameworks/base/core/java/android/service/rotationresolver/RotationResolutionRequest.java", + inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.view.Surface.Rotation int mCurrentRotation\nprivate final @android.view.Surface.Rotation int mProposedRotation\nprivate final boolean mShouldUseCamera\nprivate final @android.annotation.DurationMillisLong long mTimeoutMillis\nclass RotationResolutionRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genToString=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + } diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index c1d9d5816c9d..def13db41559 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -41,10 +41,12 @@ import android.media.permission.Identity; import android.os.AsyncTask; import android.os.Binder; import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; +import android.os.SharedMemory; import android.util.Slog; import com.android.internal.app.IHotwordRecognitionStatusCallback; @@ -287,6 +289,7 @@ public class AlwaysOnHotwordDetector { private final Handler mHandler; private final IBinder mBinder = new Binder(); private final int mTargetSdkVersion; + private final boolean mSupportHotwordDetectionService; private int mAvailability = STATE_NOT_READY; @@ -488,11 +491,22 @@ public class AlwaysOnHotwordDetector { * @param callback A non-null Callback for receiving the recognition events. * @param modelManagementService A service that allows management of sound models. * @param targetSdkVersion The target SDK version. + * @param supportHotwordDetectionService {@code true} if hotword detection service should be + * triggered, otherwise {@code false}. + * @param options Application configuration data provided by the + * {@link VoiceInteractionService}. The system strips out any remotable objects or other + * contents that can be used to communicate with other processes. + * @param sharedMemory The unrestricted data blob provided by the + * {@link VoiceInteractionService}. Use this to provide the hotword models data or other + * such data to the trusted process. + * * @hide */ public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback, KeyphraseEnrollmentInfo keyphraseEnrollmentInfo, - IVoiceInteractionManagerService modelManagementService, int targetSdkVersion) { + IVoiceInteractionManagerService modelManagementService, int targetSdkVersion, + boolean supportHotwordDetectionService, @Nullable Bundle options, + @Nullable SharedMemory sharedMemory) { mText = text; mLocale = locale; mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo; @@ -501,6 +515,10 @@ public class AlwaysOnHotwordDetector { mInternalCallback = new SoundTriggerListener(mHandler); mModelManagementService = modelManagementService; mTargetSdkVersion = targetSdkVersion; + mSupportHotwordDetectionService = supportHotwordDetectionService; + if (mSupportHotwordDetectionService) { + setHotwordDetectionServiceConfig(options, sharedMemory); + } try { Identity identity = new Identity(); identity.packageName = ActivityThread.currentOpPackageName(); @@ -513,6 +531,38 @@ public class AlwaysOnHotwordDetector { } /** + * Set configuration and pass read-only data to hotword detection service. + * + * @param options Application configuration data provided by the + * {@link VoiceInteractionService}. The system strips out any remotable objects or other + * contents that can be used to communicate with other processes. + * @param sharedMemory The unrestricted data blob provided by the + * {@link VoiceInteractionService}. Use this to provide the hotword models data or other + * such data to the trusted process. + * + * @throws IllegalStateException if it doesn't support hotword detection service. + * + * @hide + */ + public final void setHotwordDetectionServiceConfig(@Nullable Bundle options, + @Nullable SharedMemory sharedMemory) { + if (DBG) { + Slog.d(TAG, "setHotwordDetectionServiceConfig()"); + } + if (!mSupportHotwordDetectionService) { + throw new IllegalStateException( + "setHotwordDetectionServiceConfig called, but it doesn't support hotword" + + " detection service"); + } + + try { + mModelManagementService.setHotwordDetectionServiceConfig(options, sharedMemory); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Gets the recognition modes supported by the associated keyphrase. * * @see #RECOGNITION_MODE_USER_IDENTIFICATION @@ -839,6 +889,14 @@ public class AlwaysOnHotwordDetector { synchronized (mLock) { mAvailability = STATE_INVALID; notifyStateChangedLocked(); + + if (mSupportHotwordDetectionService) { + try { + mModelManagementService.shutdownHotwordDetectionService(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } } diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java index 7f1c5ff96636..fcef26f13dd0 100644 --- a/core/java/android/service/voice/HotwordDetectionService.java +++ b/core/java/android/service/voice/HotwordDetectionService.java @@ -27,13 +27,17 @@ import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; import android.media.AudioFormat; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.SharedMemory; import android.util.Log; +import java.util.Locale; + /** * Implemented by an application that wants to offer detection for hotword. The system will * start the service after calling {@link VoiceInteractionService#setHotwordDetectionConfig}. @@ -76,6 +80,17 @@ public abstract class HotwordDetectionService extends Service { timeoutMillis, new DspHotwordDetectionCallback(callback))); } + + @Override + public void setConfig(Bundle options, SharedMemory sharedMemory) throws RemoteException { + if (DBG) { + Log.d(TAG, "#setConfig"); + } + mHandler.sendMessage(obtainMessage(HotwordDetectionService::onUpdateState, + HotwordDetectionService.this, + options, + sharedMemory)); + } }; @CallSuper @@ -121,6 +136,25 @@ public abstract class HotwordDetectionService extends Service { } /** + * Called when the {@link VoiceInteractionService#createAlwaysOnHotwordDetector(String, Locale, + * Bundle, SharedMemory, AlwaysOnHotwordDetector.Callback)} or {@link AlwaysOnHotwordDetector# + * setHotwordDetectionServiceConfig(Bundle, SharedMemory)} requests an update of the hotword + * detection parameters. + * + * @param options Application configuration data provided by the + * {@link VoiceInteractionService}. The system strips out any remotable objects or other + * contents that can be used to communicate with other processes. + * @param sharedMemory The unrestricted data blob provided by the + * {@link VoiceInteractionService}. Use this to provide the hotword models data or other + * such data to the trusted process. + * + * @hide + */ + @SystemApi + public void onUpdateState(@Nullable Bundle options, @Nullable SharedMemory sharedMemory) { + } + + /** * Callback for returning the detected result. * * @hide diff --git a/core/java/android/service/voice/IHotwordDetectionService.aidl b/core/java/android/service/voice/IHotwordDetectionService.aidl index cbe76e4bf69f..8f0874a5cb2e 100644 --- a/core/java/android/service/voice/IHotwordDetectionService.aidl +++ b/core/java/android/service/voice/IHotwordDetectionService.aidl @@ -17,7 +17,9 @@ package android.service.voice; import android.media.AudioFormat; +import android.os.Bundle; import android.os.ParcelFileDescriptor; +import android.os.SharedMemory; import android.service.voice.IDspHotwordDetectionCallback; /** @@ -31,4 +33,6 @@ oneway interface IHotwordDetectionService { in AudioFormat audioFormat, long timeoutMillis, in IDspHotwordDetectionCallback callback); + + void setConfig(in Bundle options, in SharedMemory sharedMemory); } diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 25f80900f1cf..048d9f57aded 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -17,7 +17,6 @@ package android.service.voice; import android.Manifest; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -36,6 +35,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SharedMemory; import android.provider.Settings; import android.util.ArraySet; import android.util.Log; @@ -47,8 +47,6 @@ import com.android.internal.util.function.pooled.PooledLambda; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -73,32 +71,6 @@ public class VoiceInteractionService extends Service { static final String TAG = VoiceInteractionService.class.getSimpleName(); /** - * Indicates that the given configs have been set successfully after calling - * {@link VoiceInteractionService#setHotwordDetectionConfig}. - * - * @hide - */ - @SystemApi - public static final int HOTWORD_CONFIG_SUCCESS = 0; - - /** - * Indicates that the given configs have been set unsuccessfully after calling - * {@link VoiceInteractionService#setHotwordDetectionConfig}. - * - * @hide - */ - @SystemApi - public static final int HOTWORD_CONFIG_FAILURE = 1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, prefix = { "HOTWORD_CONFIG_" }, value = { - HOTWORD_CONFIG_SUCCESS, - HOTWORD_CONFIG_FAILURE, - }) - public @interface HotwordConfigResult {} - - /** * The {@link Intent} that must be declared as handled by the service. * To be supported, the service must also require the * {@link android.Manifest.permission#BIND_VOICE_INTERACTION} permission so @@ -330,42 +302,51 @@ public class VoiceInteractionService extends Service { } /** - * Set hotword detection configuration. - * - * Note: Currently it will trigger hotword detection service after calling this function when - * all conditions meet the requirements. - * - * @param options Config data. - * @return {@link VoiceInteractionService#HOTWORD_CONFIG_SUCCESS} in case of success, - * {@link VoiceInteractionService#HOTWORD_CONFIG_FAILURE} in case of failure. + * Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale. + * 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. * - * @throws IllegalStateException if the function is called before onReady() is called. + * @param keyphrase The keyphrase that's being used, for example "Hello Android". + * @param locale The locale for which the enrollment needs to be performed. + * @param callback The callback to notify of detection events. + * @return An always-on hotword detector for the given keyphrase and locale. * * @hide */ @SystemApi - @HotwordConfigResult - public final int setHotwordDetectionConfig( - @SuppressLint("NullableCollection") @Nullable Bundle options) { - if (mSystemService == null) { - throw new IllegalStateException("Not available until onReady() is called"); - } - - try { - return mSystemService.setHotwordDetectionConfig(options); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + @NonNull + public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector( + @SuppressLint("MissingNullability") String keyphrase, // TODO: nullability properly + @SuppressLint({"MissingNullability", "UseIcu"}) Locale locale, + @SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) { + return createAlwaysOnHotwordDetectorInternal(keyphrase, locale, + /* supportHotwordDetectionService= */ false, /* options= */ null, + /* sharedMemory= */ null, callback); } /** - * Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale. - * 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. + * Create an {@link AlwaysOnHotwordDetector} and trigger a {@link HotwordDetectionService} + * service, then it will also pass the read-only data to hotword detection service. + * + * Like {@see #createAlwaysOnHotwordDetector(String, Locale, AlwaysOnHotwordDetector.Callback) + * }. Before calling this function, you should set a valid hotword detection service with + * android:hotwordDetectionService in an android.voice_interaction metadata file and set + * android:isolatedProcess="true" in the AndroidManifest.xml of hotword detection service. + * Otherwise it will throw IllegalStateException. After calling this function, the system will + * also trigger a hotword detection service and pass the read-only data back to it. + * + * <p>Note: The system will trigger hotword detection service after calling this function when + * all conditions meet the requirements. * * @param keyphrase The keyphrase that's being used, for example "Hello Android". * @param locale The locale for which the enrollment needs to be performed. + * @param options Application configuration data provided by the + * {@link VoiceInteractionService}. The system strips out any remotable objects or other + * contents that can be used to communicate with other processes. + * @param sharedMemory The unrestricted data blob provided by the + * {@link VoiceInteractionService}. Use this to provide the hotword models data or other + * such data to the trusted process. * @param callback The callback to notify of detection events. * @return An always-on hotword detector for the given keyphrase and locale. * @@ -374,8 +355,22 @@ public class VoiceInteractionService extends Service { @SystemApi @NonNull public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector( - @SuppressLint("MissingNullability") String keyphrase, // TODO: annotate nullability properly + @SuppressLint("MissingNullability") String keyphrase, // TODO: nullability properly + @SuppressLint({"MissingNullability", "UseIcu"}) Locale locale, + @Nullable Bundle options, + @Nullable SharedMemory sharedMemory, + @SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) { + return createAlwaysOnHotwordDetectorInternal(keyphrase, locale, + /* supportHotwordDetectionService= */ true, options, + sharedMemory, callback); + } + + private AlwaysOnHotwordDetector createAlwaysOnHotwordDetectorInternal( + @SuppressLint("MissingNullability") String keyphrase, // TODO: nullability properly @SuppressLint({"MissingNullability", "UseIcu"}) Locale locale, + boolean supportHotwordDetectionService, + @Nullable Bundle options, + @Nullable SharedMemory sharedMemory, @SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) { if (mSystemService == null) { throw new IllegalStateException("Not available until onReady() is called"); @@ -385,7 +380,8 @@ public class VoiceInteractionService extends Service { safelyShutdownHotwordDetector(); mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback, mKeyphraseEnrollmentInfo, mSystemService, - getApplicationContext().getApplicationInfo().targetSdkVersion); + getApplicationContext().getApplicationInfo().targetSdkVersion, + supportHotwordDetectionService, options, sharedMemory); } return mHotwordDetector; } @@ -432,7 +428,6 @@ public class VoiceInteractionService extends Service { } private void safelyShutdownHotwordDetector() { - // TODO (b/178171906): Need to check if the HotwordDetectionService should be unbound. synchronized (mLock) { if (mHotwordDetector == null) { return; diff --git a/core/java/android/speech/IRecognitionServiceManager.aidl b/core/java/android/speech/IRecognitionServiceManager.aidl index 8e5292d1ddf1..ad402262878d 100644 --- a/core/java/android/speech/IRecognitionServiceManager.aidl +++ b/core/java/android/speech/IRecognitionServiceManager.aidl @@ -31,4 +31,6 @@ oneway interface IRecognitionServiceManager { in IBinder clientToken, boolean onDevice, in IRecognitionServiceManagerCallback callback); + + void setTemporaryComponent(in ComponentName componentName); } diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java index 850f997a2d2f..9b93a64e48a3 100644 --- a/core/java/android/speech/SpeechRecognizer.java +++ b/core/java/android/speech/SpeechRecognizer.java @@ -17,6 +17,8 @@ package android.speech; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.TestApi; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -35,6 +37,8 @@ import android.util.Log; import android.util.Slog; import java.util.List; +import java.util.Queue; +import java.util.concurrent.LinkedBlockingQueue; /** * This class provides access to the speech recognition service. This service allows access to the @@ -52,7 +56,7 @@ import java.util.List; */ public class SpeechRecognizer { /** DEBUG value to enable verbose debug prints */ - private final static boolean DBG = false; + private static final boolean DBG = false; /** Log messages identifier */ private static final String TAG = "SpeechRecognizer"; @@ -113,10 +117,11 @@ public class SpeechRecognizer { public static final int ERROR_SERVER_DISCONNECTED = 11; /** action codes */ - private final static int MSG_START = 1; - private final static int MSG_STOP = 2; - private final static int MSG_CANCEL = 3; - private final static int MSG_CHANGE_LISTENER = 4; + private static final int MSG_START = 1; + private static final int MSG_STOP = 2; + private static final int MSG_CANCEL = 3; + private static final int MSG_CHANGE_LISTENER = 4; + private static final int MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT = 5; /** The actual RecognitionService endpoint */ private IRecognitionService mService; @@ -134,6 +139,7 @@ public class SpeechRecognizer { /** Handler that will execute the main tasks */ private Handler mHandler = new Handler(Looper.getMainLooper()) { + @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -149,10 +155,19 @@ public class SpeechRecognizer { case MSG_CHANGE_LISTENER: handleChangeListener((RecognitionListener) msg.obj); break; + case MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT: + handleSetTemporaryComponent((ComponentName) msg.obj); + break; } } }; + /** + * Temporary queue, saving the messages until the connection will be established, afterwards, + * only mHandler will receive the messages + */ + private final Queue<Message> mPendingTasks = new LinkedBlockingQueue<>(); + /** The Listener that will receive all the callbacks */ private final InternalListener mListener = new InternalListener(); @@ -287,11 +302,9 @@ public class SpeechRecognizer { if (mService == null) { // First time connection: first establish a connection, then dispatch #startListening. - connectToSystemService( - () -> putMessage(Message.obtain(mHandler, MSG_START, recognizerIntent))); - } else { - putMessage(Message.obtain(mHandler, MSG_START, recognizerIntent)); + connectToSystemService(); } + putMessage(Message.obtain(mHandler, MSG_START, recognizerIntent)); } /** @@ -336,6 +349,22 @@ public class SpeechRecognizer { putMessage(Message.obtain(mHandler, MSG_CANCEL)); } + /** + * Sets a temporary component to power on-device speech recognizer. + * + * <p>This is only expected to be called in tests, system would reject calls from client apps. + * + * @param componentName name of the component to set temporary replace speech recognizer. {@code + * null} value resets the recognizer to default. + * + * @hide + */ + @TestApi + public void setTemporaryOnDeviceRecognizer(@Nullable ComponentName componentName) { + mHandler.sendMessage( + Message.obtain(mHandler, MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT, componentName)); + } + private static void checkIsCalledFromMainThread() { if (Looper.myLooper() != Looper.getMainLooper()) { throw new RuntimeException( @@ -344,7 +373,11 @@ public class SpeechRecognizer { } private void putMessage(Message msg) { - mHandler.sendMessage(msg); + if (mService == null) { + mPendingTasks.offer(msg); + } else { + mHandler.sendMessage(msg); + } } /** sends the actual message to the service */ @@ -395,6 +428,22 @@ public class SpeechRecognizer { } } + private void handleSetTemporaryComponent(ComponentName componentName) { + if (DBG) { + Log.d(TAG, "handleSetTemporaryComponent, componentName=" + componentName); + } + + if (!maybeInitializeManagerService()) { + return; + } + + try { + mManagerService.setTemporaryComponent(componentName); + } catch (final RemoteException e) { + e.rethrowFromSystemServer(); + } + } + private boolean checkOpenConnection() { if (mService != null) { return true; @@ -422,16 +471,13 @@ public class SpeechRecognizer { } mService = null; + mPendingTasks.clear(); mListener.mInternalListener = null; } /** Establishes a connection to system server proxy and initializes the session. */ - private void connectToSystemService(Runnable onSuccess) { - mManagerService = IRecognitionServiceManager.Stub.asInterface( - ServiceManager.getService(Context.SPEECH_RECOGNITION_SERVICE)); - - if (mManagerService == null) { - mListener.onError(ERROR_CLIENT); + private void connectToSystemService() { + if (!maybeInitializeManagerService()) { return; } @@ -450,13 +496,19 @@ public class SpeechRecognizer { new IRecognitionServiceManagerCallback.Stub(){ @Override public void onSuccess(IRecognitionService service) throws RemoteException { + if (DBG) { + Log.i(TAG, "Connected to speech recognition service"); + } mService = service; - onSuccess.run(); + while (!mPendingTasks.isEmpty()) { + mHandler.sendMessage(mPendingTasks.poll()); + } } @Override public void onError(int errorCode) throws RemoteException { - Log.e(TAG, "Bind to system recognition service failed"); + Log.e(TAG, "Bind to system recognition service failed with error " + + errorCode); mListener.onError(errorCode); } }); @@ -465,6 +517,21 @@ public class SpeechRecognizer { } } + private boolean maybeInitializeManagerService() { + if (mManagerService != null) { + return true; + } + + mManagerService = IRecognitionServiceManager.Stub.asInterface( + ServiceManager.getService(Context.SPEECH_RECOGNITION_SERVICE)); + + if (mManagerService == null && mListener != null) { + mListener.onError(ERROR_CLIENT); + return false; + } + return true; + } + /** * Returns the component name to be used for establishing a connection, based on the parameters * used during initialization. @@ -505,15 +572,15 @@ public class SpeechRecognizer { private static class InternalListener extends IRecognitionListener.Stub { private RecognitionListener mInternalListener; - private final static int MSG_BEGINNING_OF_SPEECH = 1; - private final static int MSG_BUFFER_RECEIVED = 2; - private final static int MSG_END_OF_SPEECH = 3; - private final static int MSG_ERROR = 4; - private final static int MSG_READY_FOR_SPEECH = 5; - private final static int MSG_RESULTS = 6; - private final static int MSG_PARTIAL_RESULTS = 7; - private final static int MSG_RMS_CHANGED = 8; - private final static int MSG_ON_EVENT = 9; + private static final int MSG_BEGINNING_OF_SPEECH = 1; + private static final int MSG_BUFFER_RECEIVED = 2; + private static final int MSG_END_OF_SPEECH = 3; + private static final int MSG_ERROR = 4; + private static final int MSG_READY_FOR_SPEECH = 5; + private static final int MSG_RESULTS = 6; + private static final int MSG_PARTIAL_RESULTS = 7; + private static final int MSG_RMS_CHANGED = 8; + private static final int MSG_ON_EVENT = 9; private final Handler mInternalHandler = new Handler(Looper.getMainLooper()) { @Override diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index e37921ec03cc..bbe887f500a9 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -1326,7 +1326,7 @@ public class PhoneStateListener { () -> mExecutor.execute(() -> psl.onCellLocationChanged(location))); } - public void onCallStateChanged(int state, String incomingNumber) { + public void onLegacyCallStateChanged(int state, String incomingNumber) { PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); if (psl == null) return; @@ -1334,6 +1334,10 @@ public class PhoneStateListener { () -> mExecutor.execute(() -> psl.onCallStateChanged(state, incomingNumber))); } + public void onCallStateChanged(int state) { + // Only used for the new TelephonyCallback class + } + public void onDataConnectionStateChanged(int state, int networkType) { PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); if (psl == null) return; diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java index a2584cae1b9c..2cadda25a9d3 100644 --- a/core/java/android/telephony/TelephonyCallback.java +++ b/core/java/android/telephony/TelephonyCallback.java @@ -20,11 +20,9 @@ import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.compat.annotation.ChangeId; -import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Build; import android.telephony.emergency.EmergencyNumber; @@ -170,12 +168,15 @@ public class TelephonyCallback { /** * Event for changes to the device call state. - * + * <p> + * Handles callbacks to {@link CallStateListener#onCallStateChanged(int)}. + * <p> + * Note: This is different from the legacy {@link #EVENT_LEGACY_CALL_STATE_CHANGED} listener + * which can include the phone number of the caller. We purposely do not include the phone + * number as that information is not required for call state listeners going forward. * @hide - * @see CallStateListener#onCallStateChanged */ @SystemApi - @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_CALL_STATE_CHANGED = 6; /** @@ -556,6 +557,18 @@ public class TelephonyCallback { public static final int EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED = 35; /** + * Event for changes to the legacy call state changed listener implemented by + * {@link PhoneStateListener#onCallStateChanged(int, String)}. This listener variant is similar + * to the new {@link CallStateListener#onCallStateChanged(int)} with the important distinction + * that it CAN provide the phone number associated with a call. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) + public static final int EVENT_LEGACY_CALL_STATE_CHANGED = 36; + + /** * @hide */ @IntDef(prefix = {"EVENT_"}, value = { @@ -593,7 +606,8 @@ public class TelephonyCallback { EVENT_BARRING_INFO_CHANGED, EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED, EVENT_DATA_ENABLED_CHANGED, - EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED + EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED, + EVENT_LEGACY_CALL_STATE_CHANGED }) @Retention(RetentionPolicy.SOURCE) public @interface TelephonyEvent { @@ -723,17 +737,9 @@ public class TelephonyCallback { * calling {@link TelephonyManager#getCallState()} from within this callback may return a * different state than the callback reports. * - * @param state call state - * @param phoneNumber call phone number. If application does not have - * {@link android.Manifest.permission#READ_CALL_LOG} permission or - * carrier - * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an - * empty string will be - * passed as an argument. + * @param state the current call state */ - @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) - public void onCallStateChanged(@Annotation.CallState int state, - @Nullable String phoneNumber); + public void onCallStateChanged(@Annotation.CallState int state); } /** @@ -1426,13 +1432,17 @@ public class TelephonyCallback { () -> mExecutor.execute(() -> listener.onCellLocationChanged(location))); } - public void onCallStateChanged(int state, String incomingNumber) { + public void onLegacyCallStateChanged(int state, String incomingNumber) { + // Not used for TelephonyCallback; part of the AIDL which is used by both the legacy + // PhoneStateListener and TelephonyCallback. + } + + public void onCallStateChanged(int state) { CallStateListener listener = (CallStateListener) mTelephonyCallbackWeakRef.get(); if (listener == null) return; Binder.withCleanCallingIdentity( - () -> mExecutor.execute(() -> listener.onCallStateChanged(state, - incomingNumber))); + () -> mExecutor.execute(() -> listener.onCallStateChanged(state))); } public void onDataConnectionStateChanged(int state, int networkType) { diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index 459c6e94e4ac..9cda4ae79335 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -861,6 +861,7 @@ public class TelephonyRegistryManager { eventList.add(TelephonyCallback.EVENT_CELL_LOCATION_CHANGED); } + // Note: Legacy PhoneStateListeners use EVENT_LEGACY_CALL_STATE_CHANGED if (telephonyCallback instanceof TelephonyCallback.CallStateListener) { eventList.add(TelephonyCallback.EVENT_CALL_STATE_CHANGED); } @@ -1000,8 +1001,10 @@ public class TelephonyRegistryManager { eventList.add(TelephonyCallback.EVENT_CELL_LOCATION_CHANGED); } + // Note: Legacy call state listeners can get the phone number which is not provided in the + // new version in TelephonyCallback. if ((eventMask & PhoneStateListener.LISTEN_CALL_STATE) != 0) { - eventList.add(TelephonyCallback.EVENT_CALL_STATE_CHANGED); + eventList.add(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED); } if ((eventMask & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 4d321079416b..919c6e50e3a4 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -39,7 +39,6 @@ public class FeatureFlagUtils { public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override."; public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX; public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid"; - public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press"; public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2"; /** @hide */ public static final String SETTINGS_DO_NOT_RESTORE_PRESERVED = @@ -59,7 +58,6 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_audio_switcher", "true"); DEFAULT_FLAGS.put("settings_systemui_theme", "true"); DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false"); - DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false"); DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false"); DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true"); DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "true"); diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java index c97c995641d1..7e6175c03d35 100644 --- a/core/java/android/util/apk/ApkSigningBlockUtils.java +++ b/core/java/android/util/apk/ApkSigningBlockUtils.java @@ -200,10 +200,9 @@ public final class ApkSigningBlockUtils { // physical memory. DataSource beforeApkSigningBlock = - new MemoryMappedFileDataSource(apkFileDescriptor, 0, - signatureInfo.apkSigningBlockOffset); + DataSource.create(apkFileDescriptor, 0, signatureInfo.apkSigningBlockOffset); DataSource centralDir = - new MemoryMappedFileDataSource( + DataSource.create( apkFileDescriptor, signatureInfo.centralDirOffset, signatureInfo.eocdOffset - signatureInfo.centralDirOffset); diff --git a/core/java/android/util/apk/DataSource.java b/core/java/android/util/apk/DataSource.java index 82f3800aa6d3..dd6389d012bc 100644 --- a/core/java/android/util/apk/DataSource.java +++ b/core/java/android/util/apk/DataSource.java @@ -16,6 +16,10 @@ package android.util.apk; +import android.annotation.NonNull; +import android.os.incremental.IncrementalManager; + +import java.io.FileDescriptor; import java.io.IOException; import java.security.DigestException; @@ -35,4 +39,22 @@ interface DataSource { */ void feedIntoDataDigester(DataDigester md, long offset, int size) throws IOException, DigestException; + + /** + * Creates a DataSource that can handle the passed fd in the most efficient and safe manner. + * @param fd file descriptor to read from + * @param pos starting offset + * @param size size of the region + * @return created DataSource object + */ + static @NonNull DataSource create(@NonNull FileDescriptor fd, long pos, long size) { + if (IncrementalManager.isIncrementalFileFd(fd)) { + // IncFS-based files may have missing pages, and reading those via mmap() results + // in a SIGBUS signal. Java doesn't have a good way of catching it, ending up killing + // the process by default. Going back to read() is the safest option for these files. + return new ReadFileDataSource(fd, pos, size); + } else { + return new MemoryMappedFileDataSource(fd, pos, size); + } + } } diff --git a/core/java/android/util/apk/MemoryMappedFileDataSource.java b/core/java/android/util/apk/MemoryMappedFileDataSource.java index 8d2b1e328862..69a526d09ad9 100644 --- a/core/java/android/util/apk/MemoryMappedFileDataSource.java +++ b/core/java/android/util/apk/MemoryMappedFileDataSource.java @@ -40,6 +40,7 @@ class MemoryMappedFileDataSource implements DataSource { /** * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file. * + * @param fd file descriptor to read from. * @param position start position of the region in the file. * @param size size (in bytes) of the region. */ diff --git a/core/java/android/util/apk/ReadFileDataSource.java b/core/java/android/util/apk/ReadFileDataSource.java new file mode 100644 index 000000000000..d0e1140c0eb4 --- /dev/null +++ b/core/java/android/util/apk/ReadFileDataSource.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util.apk; + +import android.system.ErrnoException; +import android.system.Os; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.DigestException; + +/** + * {@link DataSource} which provides data from a file descriptor by reading the sections + * of the file via raw read() syscall. This is slower than memory-mapping but safer. + */ +class ReadFileDataSource implements DataSource { + private final FileDescriptor mFd; + private final long mFilePosition; + private final long mSize; + + private static final int CHUNK_SIZE = 1024 * 1024; + + /** + * Constructs a new {@code ReadFileDataSource} for the specified region of the file. + * + * @param fd file descriptor to read from. + * @param position start position of the region in the file. + * @param size size (in bytes) of the region. + */ + ReadFileDataSource(FileDescriptor fd, long position, long size) { + mFd = fd; + mFilePosition = position; + mSize = size; + } + + @Override + public long size() { + return mSize; + } + + @Override + public void feedIntoDataDigester(DataDigester md, long offset, int size) + throws IOException, DigestException { + try { + final byte[] buffer = new byte[Math.min(size, CHUNK_SIZE)]; + final long start = mFilePosition + offset; + final long end = start + size; + for (long pos = start, curSize = Math.min(size, CHUNK_SIZE); + pos < end; curSize = Math.min(end - pos, CHUNK_SIZE)) { + final int readSize = Os.pread(mFd, buffer, 0, (int) curSize, pos); + md.consume(ByteBuffer.wrap(buffer, 0, readSize)); + pos += readSize; + } + } catch (ErrnoException e) { + throw new IOException(e); + } + } +} diff --git a/core/java/android/util/apk/TEST_MAPPING b/core/java/android/util/apk/TEST_MAPPING index 8544e82e04e0..4598b4ffe4f6 100644 --- a/core/java/android/util/apk/TEST_MAPPING +++ b/core/java/android/util/apk/TEST_MAPPING @@ -1,6 +1,17 @@ { "presubmit": [ { + "name": "CtsContentTestCases", + "options": [ + { + "include-filter": "android.content.pm.cts.PackageManagerShellCommandIncrementalTest" + }, + { + "include-filter": "android.content.pm.cts.PackageManagerShellCommandTest" + } + ] + }, + { "name": "FrameworksCoreTests", "options": [ { diff --git a/core/java/android/util/apk/VerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java index 4596c6e8f83d..b0a5992230bd 100644 --- a/core/java/android/util/apk/VerityBuilder.java +++ b/core/java/android/util/apk/VerityBuilder.java @@ -294,7 +294,7 @@ public abstract class VerityBuilder { // 1. Digest the whole file by chunks. consumeByChunk(digester, - new MemoryMappedFileDataSource(file.getFD(), 0, file.length()), + DataSource.create(file.getFD(), 0, file.length()), MMAP_REGION_SIZE_BYTES); // 2. Pad 0s up to the nearest 4096-byte block before hashing. @@ -315,7 +315,7 @@ public abstract class VerityBuilder { // 1. Digest from the beginning of the file, until APK Signing Block is reached. consumeByChunk(digester, - new MemoryMappedFileDataSource(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset), + DataSource.create(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset), MMAP_REGION_SIZE_BYTES); // 2. Skip APK Signing Block and continue digesting, until the Central Directory offset @@ -323,7 +323,7 @@ public abstract class VerityBuilder { long eocdCdOffsetFieldPosition = signatureInfo.eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET; consumeByChunk(digester, - new MemoryMappedFileDataSource(apk.getFD(), signatureInfo.centralDirOffset, + DataSource.create(apk.getFD(), signatureInfo.centralDirOffset, eocdCdOffsetFieldPosition - signatureInfo.centralDirOffset), MMAP_REGION_SIZE_BYTES); @@ -338,7 +338,7 @@ public abstract class VerityBuilder { long offsetAfterEocdCdOffsetField = eocdCdOffsetFieldPosition + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE; consumeByChunk(digester, - new MemoryMappedFileDataSource(apk.getFD(), offsetAfterEocdCdOffsetField, + DataSource.create(apk.getFD(), offsetAfterEocdCdOffsetField, apk.length() - offsetAfterEocdCdOffsetField), MMAP_REGION_SIZE_BYTES); diff --git a/core/java/android/util/imetracing/ImeTracing.java b/core/java/android/util/imetracing/ImeTracing.java index 49ff237403b2..b28cfb87e28d 100644 --- a/core/java/android/util/imetracing/ImeTracing.java +++ b/core/java/android/util/imetracing/ImeTracing.java @@ -23,7 +23,6 @@ import android.inputmethodservice.AbstractInputMethodService; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; -import android.os.ShellCommand; import android.util.Log; import android.util.proto.ProtoOutputStream; import android.view.inputmethod.InputMethodManager; @@ -104,12 +103,6 @@ public abstract class ImeTracing { public abstract void addToBuffer(ProtoOutputStream proto, int source); /** - * @param shell The shell command to process - * @return {@code 0} if the command was successfully processed, {@code -1} otherwise - */ - public abstract int onShellCommand(ShellCommand shell); - - /** * Starts a proto dump of the client side information. * * @param where Place where the trace was triggered. diff --git a/core/java/android/util/imetracing/ImeTracingClientImpl.java b/core/java/android/util/imetracing/ImeTracingClientImpl.java index 2c2763988d14..35a81b7aeea5 100644 --- a/core/java/android/util/imetracing/ImeTracingClientImpl.java +++ b/core/java/android/util/imetracing/ImeTracingClientImpl.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.inputmethodservice.AbstractInputMethodService; import android.os.RemoteException; import android.os.ServiceManager.ServiceNotFoundException; -import android.os.ShellCommand; import android.util.Log; import android.util.proto.ProtoOutputStream; import android.view.inputmethod.InputMethodManager; @@ -45,11 +44,6 @@ class ImeTracingClientImpl extends ImeTracing { } @Override - public int onShellCommand(ShellCommand shell) { - return -1; - } - - @Override public void triggerClientDump(String where, @NonNull InputMethodManager immInstance, ProtoOutputStream icProto) { if (!isEnabled() || !isAvailable()) { diff --git a/core/java/android/util/imetracing/ImeTracingServerImpl.java b/core/java/android/util/imetracing/ImeTracingServerImpl.java index e793c280afbc..77f017a4654a 100644 --- a/core/java/android/util/imetracing/ImeTracingServerImpl.java +++ b/core/java/android/util/imetracing/ImeTracingServerImpl.java @@ -22,7 +22,6 @@ import android.annotation.Nullable; import android.inputmethodservice.AbstractInputMethodService; import android.os.RemoteException; import android.os.ServiceManager.ServiceNotFoundException; -import android.os.ShellCommand; import android.util.Log; import android.util.proto.ProtoOutputStream; import android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceFileProto; @@ -106,32 +105,6 @@ class ImeTracingServerImpl extends ImeTracing { } } - /** - * Responds to a shell command of the format "adb shell cmd input_method ime tracing <command>" - * - * @param shell The shell command to process - * @return {@code 0} if the command was valid and successfully processed, {@code -1} otherwise - */ - @Override - public int onShellCommand(ShellCommand shell) { - PrintWriter pw = shell.getOutPrintWriter(); - String cmd = shell.getNextArgRequired(); - switch (cmd) { - case "start": - startTrace(pw); - return 0; - case "stop": - stopTrace(pw); - return 0; - default: - pw.println("Unknown command: " + cmd); - pw.println("Input method trace options:"); - pw.println(" start: Start tracing"); - pw.println(" stop: Stop tracing"); - return -1; - } - } - @Override public void triggerClientDump(String where, InputMethodManager immInstance, ProtoOutputStream icProto) { diff --git a/core/java/android/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java index 9df213b2092f..8c771baaea37 100644 --- a/core/java/android/uwb/AngleMeasurement.java +++ b/core/java/android/uwb/AngleMeasurement.java @@ -38,9 +38,30 @@ public final class AngleMeasurement implements Parcelable { private final double mErrorRadians; private final double mConfidenceLevel; - private AngleMeasurement(double radians, double errorRadians, double confidenceLevel) { + /** + * Constructs a new {@link AngleMeasurement} object + * + * @param radians the angle in radians + * @param errorRadians the error of the angle measurement in radians + * @param confidenceLevel confidence level of the angle measurement + * + * @throws IllegalArgumentException if the radians, errorRadians, or confidenceLevel is out of + * allowed range + */ + public AngleMeasurement(double radians, double errorRadians, double confidenceLevel) { + if (radians < -Math.PI || radians > Math.PI) { + throw new IllegalArgumentException("Invalid radians: " + radians); + } mRadians = radians; + + if (errorRadians < 0.0 || errorRadians > Math.PI) { + throw new IllegalArgumentException("Invalid error radians: " + errorRadians); + } mErrorRadians = errorRadians; + + if (confidenceLevel < 0.0 || confidenceLevel > 1.0) { + throw new IllegalArgumentException("Invalid confidence level: " + confidenceLevel); + } mConfidenceLevel = confidenceLevel; } @@ -122,11 +143,7 @@ public final class AngleMeasurement implements Parcelable { new Creator<AngleMeasurement>() { @Override public AngleMeasurement createFromParcel(Parcel in) { - Builder builder = new Builder(); - builder.setRadians(in.readDouble()); - builder.setErrorRadians(in.readDouble()); - builder.setConfidenceLevel(in.readDouble()); - return builder.build(); + return new AngleMeasurement(in.readDouble(), in.readDouble(), in.readDouble()); } @Override @@ -134,82 +151,4 @@ public final class AngleMeasurement implements Parcelable { return new AngleMeasurement[size]; } }; - - /** - * Builder class for {@link AngleMeasurement}. - */ - public static final class Builder { - private double mRadians = Double.NaN; - private double mErrorRadians = Double.NaN; - private double mConfidenceLevel = Double.NaN; - - /** - * Set the angle in radians - * - * @param radians angle in radians - * @throws IllegalArgumentException if angle exceeds allowed limits of [-Math.PI, +Math.PI] - */ - @NonNull - public Builder setRadians(double radians) { - if (radians < -Math.PI || radians > Math.PI) { - throw new IllegalArgumentException("Invalid radians: " + radians); - } - mRadians = radians; - return this; - } - - /** - * Set the angle error in radians - * - * @param errorRadians error of the angle in radians - * @throws IllegalArgumentException if the error exceeds the allowed limits of [0, +Math.PI] - */ - @NonNull - public Builder setErrorRadians(double errorRadians) { - if (errorRadians < 0.0 || errorRadians > Math.PI) { - throw new IllegalArgumentException( - "Invalid error radians: " + errorRadians); - } - mErrorRadians = errorRadians; - return this; - } - - /** - * Set the angle confidence level - * - * @param confidenceLevel level of confidence of the angle measurement - * @throws IllegalArgumentException if the error exceeds the allowed limits of [0.0, 1.0] - */ - @NonNull - public Builder setConfidenceLevel(double confidenceLevel) { - if (confidenceLevel < 0.0 || confidenceLevel > 1.0) { - throw new IllegalArgumentException( - "Invalid confidence level: " + confidenceLevel); - } - mConfidenceLevel = confidenceLevel; - return this; - } - - /** - * Build the {@link AngleMeasurement} object - * - * @throws IllegalStateException if angle, error, or confidence values are missing - */ - @NonNull - public AngleMeasurement build() { - if (Double.isNaN(mRadians)) { - throw new IllegalStateException("Angle is not set"); - } - - if (Double.isNaN(mErrorRadians)) { - throw new IllegalStateException("Angle error is not set"); - } - - if (Double.isNaN(mConfidenceLevel)) { - throw new IllegalStateException("Angle confidence level is not set"); - } - - return new AngleMeasurement(mRadians, mErrorRadians, mConfidenceLevel); - } - } } diff --git a/core/java/android/uwb/AngleOfArrivalMeasurement.java b/core/java/android/uwb/AngleOfArrivalMeasurement.java index 3d8626b98bed..db04ad16c191 100644 --- a/core/java/android/uwb/AngleOfArrivalMeasurement.java +++ b/core/java/android/uwb/AngleOfArrivalMeasurement.java @@ -116,9 +116,8 @@ public final class AngleOfArrivalMeasurement implements Parcelable { new Creator<AngleOfArrivalMeasurement>() { @Override public AngleOfArrivalMeasurement createFromParcel(Parcel in) { - Builder builder = new Builder(); - - builder.setAzimuth(in.readParcelable(AngleMeasurement.class.getClassLoader())); + Builder builder = + new Builder(in.readParcelable(AngleMeasurement.class.getClassLoader())); builder.setAltitude(in.readParcelable(AngleMeasurement.class.getClassLoader())); @@ -135,18 +134,16 @@ public final class AngleOfArrivalMeasurement implements Parcelable { * Builder class for {@link AngleOfArrivalMeasurement}. */ public static final class Builder { - private AngleMeasurement mAzimuthAngleMeasurement = null; + private final AngleMeasurement mAzimuthAngleMeasurement; private AngleMeasurement mAltitudeAngleMeasurement = null; /** - * Set the azimuth angle + * Constructs an {@link AngleOfArrivalMeasurement} object * - * @param azimuthAngle azimuth angle + * @param azimuthAngle the azimuth angle of the measurement */ - @NonNull - public Builder setAzimuth(@NonNull AngleMeasurement azimuthAngle) { + public Builder(@NonNull AngleMeasurement azimuthAngle) { mAzimuthAngleMeasurement = azimuthAngle; - return this; } /** @@ -162,15 +159,9 @@ public final class AngleOfArrivalMeasurement implements Parcelable { /** * Build the {@link AngleOfArrivalMeasurement} object - * - * @throws IllegalStateException if the required azimuth angle is not provided */ @NonNull public AngleOfArrivalMeasurement build() { - if (mAzimuthAngleMeasurement == null) { - throw new IllegalStateException("Azimuth angle measurement is not set"); - } - return new AngleOfArrivalMeasurement(mAzimuthAngleMeasurement, mAltitudeAngleMeasurement); } diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl index 468a69c7bddb..4036892fb9e7 100644 --- a/core/java/android/uwb/IUwbAdapter.aidl +++ b/core/java/android/uwb/IUwbAdapter.aidl @@ -62,9 +62,6 @@ interface IUwbAdapter { /** * Request to open a new ranging session * - * This function must return before calling any functions in - * IUwbAdapterCallbacks. - * * This function does not start the ranging session, but all necessary * components must be initialized and ready to start a new ranging * session prior to calling IUwbAdapterCallback#onRangingOpened. @@ -77,12 +74,16 @@ interface IUwbAdapter { * RANGING_SESSION_OPEN_THRESHOLD_MS milliseconds of #openRanging being called * if the ranging session fails to be opened. * + * If the provided sessionHandle is already open for the calling client, then + * #onRangingOpenFailed must be called and the new session must not be opened. + * + * @param sessionHandle the session handle to open ranging for * @param rangingCallbacks the callbacks used to deliver ranging information * @param parameters the configuration to use for ranging - * @return a SessionHandle used to identify this ranging request */ - SessionHandle openRanging(in IUwbRangingCallbacks rangingCallbacks, - in PersistableBundle parameters); + void openRanging(in SessionHandle sessionHandle, + in IUwbRangingCallbacks rangingCallbacks, + in PersistableBundle parameters); /** * Request to start ranging diff --git a/core/java/android/uwb/RangingManager.java b/core/java/android/uwb/RangingManager.java index c0d818774ba0..85f2c1ccc180 100644 --- a/core/java/android/uwb/RangingManager.java +++ b/core/java/android/uwb/RangingManager.java @@ -17,6 +17,7 @@ package android.uwb; import android.annotation.NonNull; +import android.os.CancellationSignal; import android.os.PersistableBundle; import android.os.RemoteException; import android.util.Log; @@ -32,6 +33,7 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub { private final IUwbAdapter mAdapter; private final Hashtable<SessionHandle, RangingSession> mRangingSessionTable = new Hashtable<>(); + private int mNextSessionId = 1; public RangingManager(IUwbAdapter adapter) { mAdapter = adapter; @@ -44,29 +46,26 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub { * @param executor {@link Executor} to run callbacks * @param callbacks {@link RangingSession.Callback} to associate with the {@link RangingSession} * that is being opened. - * @return a new {@link RangingSession} + * @return a {@link CancellationSignal} that may be used to cancel the opening of the + * {@link RangingSession}. */ - public RangingSession openSession(@NonNull PersistableBundle params, @NonNull Executor executor, + public CancellationSignal openSession(@NonNull PersistableBundle params, + @NonNull Executor executor, @NonNull RangingSession.Callback callbacks) { - SessionHandle sessionHandle; - try { - sessionHandle = mAdapter.openRanging(this, params); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - synchronized (this) { - if (hasSession(sessionHandle)) { - Log.w(TAG, "Newly created session unexpectedly reuses an active SessionHandle"); - executor.execute(() -> callbacks.onClosed( - RangingSession.Callback.REASON_GENERIC_ERROR, - new PersistableBundle())); - } - + SessionHandle sessionHandle = new SessionHandle(mNextSessionId++); RangingSession session = new RangingSession(executor, callbacks, mAdapter, sessionHandle); mRangingSessionTable.put(sessionHandle, session); - return session; + try { + mAdapter.openRanging(sessionHandle, this, params); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + CancellationSignal cancellationSignal = new CancellationSignal(); + cancellationSignal.setOnCancelListener(() -> session.close()); + return cancellationSignal; } } diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java index 63a6d058f358..844bbbe7970b 100644 --- a/core/java/android/uwb/UwbManager.java +++ b/core/java/android/uwb/UwbManager.java @@ -25,6 +25,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; +import android.os.CancellationSignal; import android.os.IBinder; import android.os.PersistableBundle; import android.os.RemoteException; @@ -228,14 +229,14 @@ public final class UwbManager { * @param callbacks {@link RangingSession.Callback} to associate with the * {@link RangingSession} that is being opened. * - * @return an {@link AutoCloseable} that is able to be used to close or cancel the opening of a + * @return an {@link CancellationSignal} that is able to be used to cancel the opening of a * {@link RangingSession} that has been requested through {@link #openRangingSession} * but has not yet been made available by * {@link RangingSession.Callback#onOpened(RangingSession)}. */ @NonNull @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public AutoCloseable openRangingSession(@NonNull PersistableBundle parameters, + public CancellationSignal openRangingSession(@NonNull PersistableBundle parameters, @NonNull @CallbackExecutor Executor executor, @NonNull RangingSession.Callback callbacks) { return mRangingManager.openSession(parameters, executor, callbacks); diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index d138b4b41450..d484f4d47e99 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -24,8 +24,11 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.TestApi; +import android.app.ActivityThread; import android.app.KeyguardManager; +import android.app.WindowConfiguration; import android.compat.annotation.UnsupportedAppUsage; +import android.content.ComponentName; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; @@ -44,11 +47,14 @@ import android.os.SystemClock; import android.util.DisplayMetrics; import android.util.Log; +import com.android.internal.R; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Optional; /** * Provides information about the size and density of a logical display. @@ -78,6 +84,7 @@ public final class Display { private static final String TAG = "Display"; private static final boolean DEBUG = false; + private final Object mLock = new Object(); private final DisplayManagerGlobal mGlobal; private final int mDisplayId; private final int mFlags; @@ -112,6 +119,12 @@ public final class Display { private boolean mMayAdjustByFixedRotation; /** + * Cache if the application is the recents component. + * TODO(b/179308296) Remove once Launcher addresses issue + */ + private Optional<Boolean> mIsRecentsComponent = Optional.empty(); + + /** * The default Display id, which is the id of the primary display assuming there is one. */ public static final int DEFAULT_DISPLAY = 0; @@ -557,7 +570,7 @@ public final class Display { * @return True if the display is still valid. */ public boolean isValid() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mIsValid; } @@ -572,7 +585,7 @@ public final class Display { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public boolean getDisplayInfo(DisplayInfo outDisplayInfo) { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); outDisplayInfo.copyFrom(mDisplayInfo); return mIsValid; @@ -589,7 +602,7 @@ public final class Display { * @hide */ public int getLayerStack() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.layerStack; } @@ -636,7 +649,7 @@ public final class Display { * @hide */ public DisplayAddress getAddress() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.address; } @@ -678,9 +691,9 @@ public final class Display { @UnsupportedAppUsage public DisplayAdjustments getDisplayAdjustments() { if (mResources != null) { - final DisplayAdjustments currentAdjustements = mResources.getDisplayAdjustments(); - if (!mDisplayAdjustments.equals(currentAdjustements)) { - mDisplayAdjustments = new DisplayAdjustments(currentAdjustements); + final DisplayAdjustments currentAdjustments = mResources.getDisplayAdjustments(); + if (!mDisplayAdjustments.equals(currentAdjustments)) { + mDisplayAdjustments = new DisplayAdjustments(currentAdjustments); } } @@ -696,7 +709,7 @@ public final class Display { * @return The display's name. */ public String getName() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.name; } @@ -709,7 +722,7 @@ public final class Display { * @hide */ public float getBrightnessDefault() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.brightnessDefault; } @@ -748,7 +761,7 @@ public final class Display { */ @Deprecated public void getSize(Point outSize) { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments()); outSize.x = mTempMetrics.widthPixels; @@ -765,7 +778,7 @@ public final class Display { */ @Deprecated public void getRectSize(Rect outSize) { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments()); outSize.set(0, 0, mTempMetrics.widthPixels, mTempMetrics.heightPixels); @@ -803,7 +816,7 @@ public final class Display { * for example, screen decorations like the status bar are being hidden. */ public void getCurrentSizeRange(Point outSmallestSize, Point outLargestSize) { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); outSmallestSize.x = mDisplayInfo.smallestNominalAppWidth; outSmallestSize.y = mDisplayInfo.smallestNominalAppHeight; @@ -819,7 +832,7 @@ public final class Display { */ @UnsupportedAppUsage public int getMaximumSizeDimension() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return Math.max(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); } @@ -830,7 +843,7 @@ public final class Display { */ @Deprecated public int getWidth() { - synchronized (this) { + synchronized (mLock) { updateCachedAppSizeIfNeededLocked(); return mCachedAppWidthCompat; } @@ -841,7 +854,7 @@ public final class Display { */ @Deprecated public int getHeight() { - synchronized (this) { + synchronized (mLock) { updateCachedAppSizeIfNeededLocked(); return mCachedAppHeightCompat; } @@ -866,7 +879,7 @@ public final class Display { */ @Surface.Rotation public int getRotation() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mMayAdjustByFixedRotation ? getDisplayAdjustments().getRotation(mDisplayInfo.rotation) @@ -892,7 +905,7 @@ public final class Display { */ @Nullable public DisplayCutout getCutout() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mMayAdjustByFixedRotation ? getDisplayAdjustments().getDisplayCutout(mDisplayInfo.displayCutout) @@ -910,7 +923,7 @@ public final class Display { @SuppressLint("VisiblySynchronized") @Nullable public RoundedCorner getRoundedCorner(@RoundedCorner.Position int position) { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); RoundedCorners roundedCorners; if (mMayAdjustByFixedRotation) { @@ -942,7 +955,7 @@ public final class Display { * Gets the refresh rate of this display in frames per second. */ public float getRefreshRate() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.getRefreshRate(); } @@ -958,7 +971,7 @@ public final class Display { */ @Deprecated public float[] getSupportedRefreshRates() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.getDefaultRefreshRates(); } @@ -968,7 +981,7 @@ public final class Display { * Returns the active mode of the display. */ public Mode getMode() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.getMode(); } @@ -978,7 +991,7 @@ public final class Display { * Gets the supported modes of this display. */ public Mode[] getSupportedModes() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); final Display.Mode[] modes = mDisplayInfo.supportedModes; return Arrays.copyOf(modes, modes.length); @@ -1004,7 +1017,7 @@ public final class Display { */ @SuppressLint("VisiblySynchronized") public boolean isMinimalPostProcessingSupported() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.minimalPostProcessingSupported; } @@ -1024,7 +1037,7 @@ public final class Display { * @hide */ public int getColorMode() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.colorMode; } @@ -1051,7 +1064,7 @@ public final class Display { * @see #isHdr() */ public HdrCapabilities getHdrCapabilities() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.hdrCapabilities; } @@ -1064,7 +1077,7 @@ public final class Display { * @see HdrCapabilities#getSupportedHdrTypes() */ public boolean isHdr() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.isHdr(); } @@ -1077,7 +1090,7 @@ public final class Display { * {@link Configuration#isScreenWideColorGamut()}. */ public boolean isWideColorGamut() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.isWideColorGamut(); } @@ -1092,7 +1105,7 @@ public final class Display { */ @Nullable public ColorSpace getPreferredWideGamutColorSpace() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); if (mDisplayInfo.isWideColorGamut()) { return mGlobal.getPreferredWideGamutColorSpace(); @@ -1106,7 +1119,7 @@ public final class Display { * @hide */ public int[] getSupportedColorModes() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); int[] colorModes = mDisplayInfo.supportedColorModes; return Arrays.copyOf(colorModes, colorModes.length); @@ -1123,7 +1136,7 @@ public final class Display { @NonNull @TestApi public @ColorMode ColorSpace[] getSupportedWideColorGamut() { - synchronized (this) { + synchronized (mLock) { final ColorSpace[] defaultColorSpaces = new ColorSpace[0]; updateDisplayInfoLocked(); if (!isWideColorGamut()) { @@ -1157,7 +1170,7 @@ public final class Display { * A/V synchronization. */ public long getAppVsyncOffsetNanos() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.appVsyncOffsetNanos; } @@ -1175,7 +1188,7 @@ public final class Display { * ({@link System#nanoTime}). */ public long getPresentationDeadlineNanos() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mDisplayInfo.presentationDeadlineNanos; } @@ -1190,7 +1203,10 @@ public final class Display { */ @Nullable public DeviceProductInfo getDeviceProductInfo() { - return mDisplayInfo.deviceProductInfo; + synchronized (mLock) { + updateDisplayInfoLocked(); + return mDisplayInfo.deviceProductInfo; + } } /** @@ -1223,7 +1239,7 @@ public final class Display { */ @Deprecated public void getMetrics(DisplayMetrics outMetrics) { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); mDisplayInfo.getAppMetrics(outMetrics, getDisplayAdjustments()); } @@ -1276,8 +1292,20 @@ public final class Display { */ @Deprecated public void getRealSize(Point outSize) { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); + if (shouldReportMaxBounds()) { + final Rect bounds = mResources.getConfiguration() + .windowConfiguration.getMaxBounds(); + outSize.x = bounds.width(); + outSize.y = bounds.height(); + if (DEBUG) { + Log.d(TAG, "getRealSize determined from max bounds: " + outSize); + } + // Skip adjusting by fixed rotation, since if it is necessary, the configuration + // should already reflect the expected rotation. + return; + } outSize.x = mDisplayInfo.logicalWidth; outSize.y = mDisplayInfo.logicalHeight; if (mMayAdjustByFixedRotation) { @@ -1334,8 +1362,19 @@ public final class Display { */ @Deprecated public void getRealMetrics(DisplayMetrics outMetrics) { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); + if (shouldReportMaxBounds()) { + mDisplayInfo.getMaxBoundsMetrics(outMetrics, + CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, + mResources.getConfiguration()); + if (DEBUG) { + Log.d(TAG, "getRealMetrics determined from max bounds: " + outMetrics); + } + // Skip adjusting by fixed rotation, since if it is necessary, the configuration + // should already reflect the expected rotation. + return; + } mDisplayInfo.getLogicalMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); if (mMayAdjustByFixedRotation) { @@ -1345,6 +1384,53 @@ public final class Display { } /** + * Determines if {@link WindowConfiguration#getMaxBounds()} should be reported as the + * display dimensions. The max bounds field may be smaller than the logical dimensions + * when apps need to be sandboxed. + * + * Depends upon {@link WindowConfiguration#getMaxBounds()} being set in + * {@link com.android.server.wm.ConfigurationContainer#providesMaxBounds()}. In most cases, this + * value reflects the size of the current DisplayArea. + * @return {@code true} when max bounds should be applied. + */ + private boolean shouldReportMaxBounds() { + if (mResources == null) { + return false; + } + final Configuration config = mResources.getConfiguration(); + // TODO(b/179308296) Temporarily exclude Launcher from being given max bounds, by checking + // if the caller is the recents component. + return config != null && !config.windowConfiguration.getMaxBounds().isEmpty() + && !isRecentsComponent(); + } + + /** + * Returns {@code true} when the calling package is the recents component. + * TODO(b/179308296) Remove once Launcher addresses issue + */ + boolean isRecentsComponent() { + if (mIsRecentsComponent.isPresent()) { + return mIsRecentsComponent.get(); + } + if (mResources == null) { + return false; + } + try { + String recentsComponent = mResources.getString(R.string.config_recentsComponentName); + if (recentsComponent == null) { + return false; + } + String recentsPackage = ComponentName.unflattenFromString(recentsComponent) + .getPackageName(); + mIsRecentsComponent = Optional.of(recentsPackage != null + && recentsPackage.equals(ActivityThread.currentPackageName())); + return mIsRecentsComponent.get(); + } catch (Resources.NotFoundException e) { + return false; + } + } + + /** * Gets the state of the display, such as whether it is on or off. * * @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON}, @@ -1352,7 +1438,7 @@ public final class Display { * {@link #STATE_UNKNOWN}. */ public int getState() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); return mIsValid ? mDisplayInfo.state : STATE_UNKNOWN; } @@ -1436,7 +1522,7 @@ public final class Display { // For debugging purposes @Override public String toString() { - synchronized (this) { + synchronized (mLock) { updateDisplayInfoLocked(); final DisplayAdjustments adjustments = getDisplayAdjustments(); mDisplayInfo.getAppMetrics(mTempMetrics, adjustments); diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 655f42308a1f..9aaf5c066073 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -24,6 +24,7 @@ import static android.view.DisplayInfoProto.LOGICAL_WIDTH; import static android.view.DisplayInfoProto.NAME; import android.annotation.Nullable; +import android.app.WindowConfiguration; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; @@ -615,11 +616,31 @@ public final class DisplayInfo implements Parcelable { getMetricsWithSize(outMetrics, ci, configuration, appWidth, appHeight); } + /** + * Populates {@code outMetrics} with details of the logical display. Bounds are limited + * by the logical size of the display. + * + * @param outMetrics the {@link DisplayMetrics} to be populated + * @param compatInfo the {@link CompatibilityInfo} to be applied + * @param configuration the {@link Configuration} + */ public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo, Configuration configuration) { getMetricsWithSize(outMetrics, compatInfo, configuration, logicalWidth, logicalHeight); } + /** + * Similar to {@link #getLogicalMetrics}, but the limiting bounds are determined from + * {@link WindowConfiguration#getMaxBounds()} + */ + public void getMaxBoundsMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo, + Configuration configuration) { + Rect bounds = configuration.windowConfiguration.getMaxBounds(); + // Pass in null configuration to ensure width and height are not overridden to app bounds. + getMetricsWithSize(outMetrics, compatInfo, /* configuration= */ null, + bounds.width(), bounds.height()); + } + public int getNaturalWidth() { return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ? logicalWidth : logicalHeight; diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index afbd2493bad4..ddb49786dce6 100644 --- a/core/java/android/view/IRecentsAnimationController.aidl +++ b/core/java/android/view/IRecentsAnimationController.aidl @@ -142,7 +142,13 @@ interface IRecentsAnimationController { * * The system reparents the leash of navigation bar to the app when the recents animation starts * and Launcher should call this method to let system restore the navigation bar to its - * original position when the quick switch gesture is finished. + * original position when the quick switch gesture is finished and will run the fade-in + * animation If {@param moveHomeToTop} is {@code true}. Otherwise, restore the navigtation bar + * without animation. + * + * @param moveHomeToTop if {@code true}, the home activity should be moved to the top. + * Otherwise, the home activity is hidden and the user is returned to the + * app. */ - void detachNavigationBarFromApp(); + void detachNavigationBarFromApp(boolean moveHomeToTop); } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 54778007c6ff..b345b2e58252 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -816,4 +816,6 @@ interface IWindowManager * @param listener the listener to be unregistered */ void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener); + + void setForceCrossWindowBlurDisabled(boolean disable); } diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java index 79d8c14aa0df..5e0579d8a672 100644 --- a/core/java/android/view/InputEventReceiver.java +++ b/core/java/android/view/InputEventReceiver.java @@ -159,6 +159,16 @@ public abstract class InputEventReceiver { } /** + * Called when a drag event is received, from native code. + * + * @param isExiting if false, the window associated with this input channel has just received + * drag + * if true, the window associated with this input channel has just lost drag + */ + public void onDragEvent(boolean isExiting, float x, float y) { + } + + /** * Called when a batched input event is pending. * * The batched input event will continue to accumulate additional movement diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS index cbb86de4785f..31f6f6afdd53 100644 --- a/core/java/android/view/OWNERS +++ b/core/java/android/view/OWNERS @@ -78,3 +78,8 @@ per-file SyncRtSurfaceTransactionApplier.java = file:/services/core/java/com/and per-file ViewRootInsetsControllerHost.java = file:/services/core/java/com/android/server/wm/OWNERS per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS per-file Window*.aidl = file:/services/core/java/com/android/server/wm/OWNERS + +# Scroll Capture +per-file *ScrollCapture*.aidl = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS +per-file *CaptureHelper*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 9fc415d6401f..35726c0c1f04 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -8572,6 +8572,17 @@ public final class ViewRootImpl implements ViewParent, } @Override + public void onDragEvent(boolean isExiting, float x, float y) { + // force DRAG_EXITED_EVENT if appropriate + DragEvent event = DragEvent.obtain( + isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION, + x, y, 0 /* offsetX */, 0 /* offsetY */, null/* localState */, + null/* description */, null /* data */, null /* dragSurface */, + null /* dragAndDropPermissions */, false /* result */); + dispatchDragEvent(event); + } + + @Override public void dispose() { unscheduleConsumeBatchedInput(); super.dispose(); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 7338c7d9a581..818a2b04b5c0 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -873,6 +873,20 @@ public interface WindowManager extends ViewManager { default void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { } + /** + * 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) { + } + public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable { /** * X position for this window. With the default gravity it is ignored. diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index b39870738d68..e37522bc9986 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -317,4 +317,13 @@ public final class WindowManagerImpl implements WindowManager { public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { CrossWindowBlurListeners.getInstance().removeListener(listener); } + + @Override + public void setForceCrossWindowBlurDisabled(boolean disable) { + try { + WindowManagerGlobal.getWindowManagerService() + .setForceCrossWindowBlurDisabled(disable); + } catch (RemoteException e) { + } + } } diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 9523bcdb8e39..ed840ce3061b 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -70,7 +70,7 @@ import java.util.function.Consumer; * <p>Content capture provides real-time, continuous capture of application activity, display and * events to an intelligence service that is provided by the Android system. The intelligence * service then uses that info to mediate and speed user journey through different apps. For - * example, when the user receives a restaurant address in a chat app and switchs to a map app + * example, when the user receives a restaurant address in a chat app and switches to a map app * to search for that restaurant, the intelligence service could offer an autofill dialog to * let the user automatically select its address. * diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java index de4554b9e624..6ade5e622eab 100644 --- a/core/java/android/view/inputmethod/InputMethod.java +++ b/core/java/android/view/inputmethod/InputMethod.java @@ -105,7 +105,7 @@ public interface InputMethod { */ @MainThread default void initializeInternal(IBinder token, int displayId, - IInputMethodPrivilegedOperations privilegedOperations) { + IInputMethodPrivilegedOperations privilegedOperations, int configChanges) { updateInputMethodDisplay(displayId); attachToken(token); } diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index 5d876a6f62d3..25712f8bf9b8 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -18,19 +18,23 @@ package android.view.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; +import android.inputmethodservice.InputMethodService; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; @@ -60,6 +64,7 @@ import java.util.List; * @attr ref android.R.styleable#InputMethod_isDefault * @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions + * @attr ref android.R.styleable#InputMethod_configChanges */ public final class InputMethodInfo implements Parcelable { static final String TAG = "InputMethodInfo"; @@ -118,6 +123,12 @@ public final class InputMethodInfo implements Parcelable { private final boolean mInlineSuggestionsEnabled; /** + * The flag for configurations IME assumes the responsibility for handling in + * {@link InputMethodService#onConfigurationChanged(Configuration)}}. + */ + private final int mHandledConfigChanges; + + /** * @param service the {@link ResolveInfo} corresponds in which the IME is implemented. * @return a unique ID to be returned by {@link #getId()}. We have used * {@link ComponentName#flattenToShortString()} for this purpose (and it is already @@ -203,6 +214,8 @@ public final class InputMethodInfo implements Parcelable { false); inlineSuggestionsEnabled = sa.getBoolean( com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false); + mHandledConfigChanges = sa.getInt( + com.android.internal.R.styleable.InputMethod_configChanges, 0); sa.recycle(); final int depth = parser.getDepth(); @@ -287,6 +300,7 @@ public final class InputMethodInfo implements Parcelable { mIsVrOnly = source.readBoolean(); mService = ResolveInfo.CREATOR.createFromParcel(source); mSubtypes = new InputMethodSubtypeArray(source); + mHandledConfigChanges = source.readInt(); mForceDefault = false; } @@ -298,7 +312,22 @@ public final class InputMethodInfo implements Parcelable { this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */, settingsActivity, null /* subtypes */, 0 /* isDefaultResId */, false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */, - false /* inlineSuggestionsEnabled */, false /* isVrOnly */); + false /* inlineSuggestionsEnabled */, false /* isVrOnly */, + 0 /* handledConfigChanges */); + } + + /** + * Temporary API for creating a built-in input method for test. + * @hide + */ + @TestApi + public InputMethodInfo(@NonNull String packageName, @NonNull String className, + @NonNull CharSequence label, @NonNull String settingsActivity, + int handledConfigChanges) { + this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */, + settingsActivity, null /* subtypes */, 0 /* isDefaultResId */, + false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */, + false /* inlineSuggestionsEnabled */, false /* isVrOnly */, handledConfigChanges); } /** @@ -310,7 +339,7 @@ public final class InputMethodInfo implements Parcelable { boolean forceDefault) { this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault, true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */, - false /* isVrOnly */); + false /* isVrOnly */, 0 /* handledconfigChanges */); } /** @@ -321,7 +350,8 @@ public final class InputMethodInfo implements Parcelable { List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault, boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) { this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault, - supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly); + supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly, + 0 /* handledConfigChanges */); } /** @@ -331,7 +361,7 @@ public final class InputMethodInfo implements Parcelable { public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault, boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled, - boolean isVrOnly) { + boolean isVrOnly, int handledConfigChanges) { final ServiceInfo si = ri.serviceInfo; mService = ri; mId = new ComponentName(si.packageName, si.name).flattenToShortString(); @@ -343,6 +373,7 @@ public final class InputMethodInfo implements Parcelable { mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod; mInlineSuggestionsEnabled = inlineSuggestionsEnabled; mIsVrOnly = isVrOnly; + mHandledConfigChanges = handledConfigChanges; } private static ResolveInfo buildFakeResolveInfo(String packageName, String className, @@ -489,6 +520,17 @@ public final class InputMethodInfo implements Parcelable { } } + /** + * Returns the bit mask of kinds of configuration changes that this IME + * can handle itself (without being restarted by the system). + * + * @attr ref android.R.styleable#InputMethod_configChanges + */ + @ActivityInfo.Config + public int getConfigChanges() { + return mHandledConfigChanges; + } + public void dump(Printer pw, String prefix) { pw.println(prefix + "mId=" + mId + " mSettingsActivityName=" + mSettingsActivityName @@ -579,6 +621,7 @@ public final class InputMethodInfo implements Parcelable { dest.writeBoolean(mIsVrOnly); mService.writeToParcel(dest, flags); mSubtypes.writeToParcel(dest); + dest.writeInt(mHandledConfigChanges); } /** diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index a8fff8bb6a43..53bbc0ab1a02 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -106,7 +106,6 @@ import com.android.internal.view.InputBindResult; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.lang.ref.WeakReference; import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.Collections; @@ -413,7 +412,7 @@ public final class InputMethodManager { * The InputConnection that was last retrieved from the served view. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - ControlledInputConnectionWrapper mServedInputConnectionWrapper; + IInputConnectionWrapper mServedInputConnectionWrapper; /** * The completions that were last provided by the served view. */ @@ -740,8 +739,7 @@ public final class InputMethodManager { /** * Checks whether the active input connection (if any) is for the given view. * - * TODO(b/160968797): Remove this method and move mServedInputConnectionWrapper to - * ImeFocusController. + * TODO(b/182259171): Clean-up hasActiveConnection to simplify the logic. * * Note that this method is only intended for restarting input after focus gain * (e.g. b/160391516), DO NOT leverage this method to do another check. @@ -755,7 +753,7 @@ public final class InputMethodManager { return mServedInputConnectionWrapper != null && mServedInputConnectionWrapper.isActive() - && mServedInputConnectionWrapper.mServedView.get() == view; + && mServedInputConnectionWrapper.getServedView() == view; } } } @@ -1022,77 +1020,6 @@ public final class InputMethodManager { } } - private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper { - private final InputMethodManager mParentInputMethodManager; - private final WeakReference<View> mServedView; - - ControlledInputConnectionWrapper(Looper icLooper, InputConnection conn, - InputMethodManager inputMethodManager, View servedView) { - super(icLooper, conn); - mParentInputMethodManager = inputMethodManager; - mServedView = new WeakReference<>(servedView); - } - - @Override - public boolean isActive() { - return mParentInputMethodManager.mActive && !isFinished(); - } - - @Override - public InputMethodManager getIMM() { - return mParentInputMethodManager; - } - - void deactivate() { - if (isFinished()) { - // This is a small performance optimization. Still only the 1st call of - // reportFinish() will take effect. - return; - } - closeConnection(); - - // Notify the app that the InputConnection was closed. - final View servedView = mServedView.get(); - if (servedView != null) { - final Handler handler = servedView.getHandler(); - // The handler is null if the view is already detached. When that's the case, for - // now, we simply don't dispatch this callback. - if (handler != null) { - if (DEBUG) { - Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView); - } - if (handler.getLooper().isCurrentThread()) { - servedView.onInputConnectionClosedInternal(); - } else { - handler.post(servedView::onInputConnectionClosedInternal); - } - } - } - } - - @Override - public String toString() { - return "ControlledInputConnectionWrapper{" - + "connection=" + getInputConnection() - + " finished=" + isFinished() - + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive - + " mServedView=" + mServedView.get() - + "}"; - } - - void dumpDebug(ProtoOutputStream proto, long fieldId) { - // Check that the call is initiated in the main thread of the current InputConnection - // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are - // executed on this thread. Otherwise the messages are dispatched to the correct thread - // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance - // reasons. - if (getInputConnection() instanceof DumpableInputConnection && Looper.myLooper() - == getLooper()) { - ((DumpableInputConnection) getInputConnection()).dumpDebug(proto, fieldId); - } - } - } - final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() { @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { @@ -1256,8 +1183,7 @@ public final class InputMethodManager { mMainLooper = looper; mH = new H(looper); mDisplayId = displayId; - mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this, - null); + mIInputContext = new IInputConnectionWrapper(looper, mDummyInputConnection, this, null); } /** @@ -2063,7 +1989,7 @@ public final class InputMethodManager { mServedInputConnectionWrapper.deactivate(); mServedInputConnectionWrapper = null; } - ControlledInputConnectionWrapper servedContext; + IInputConnectionWrapper servedContext; final int missingMethodFlags; if (ic != null) { mCursorSelStart = tba.initialSelStart; @@ -2080,7 +2006,7 @@ public final class InputMethodManager { } else { icHandler = ic.getHandler(); } - servedContext = new ControlledInputConnectionWrapper( + servedContext = new IInputConnectionWrapper( icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view); } else { servedContext = null; diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java index cf3358b0dfbb..9f90b3bf1322 100644 --- a/core/java/android/view/translation/UiTranslationController.java +++ b/core/java/android/view/translation/UiTranslationController.java @@ -25,6 +25,7 @@ import android.annotation.NonNull; import android.annotation.WorkerThread; import android.app.Activity; import android.content.Context; +import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; @@ -54,6 +55,11 @@ import java.util.function.Consumer; */ public class UiTranslationController { + // TODO(b/182433547): remove Build.IS_DEBUGGABLE before ship. Enable the logging in debug build + // to help the debug during the development phase + public static final boolean DEBUG = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG) + || Build.IS_DEBUGGABLE; + private static final String TAG = "UiTranslationController"; @NonNull private final Activity mActivity; @@ -93,6 +99,8 @@ public class UiTranslationController { if (!mActivity.isResumed()) { return; } + Log.i(TAG, "updateUiTranslationState state: " + stateToString(state) + + (DEBUG ? ", views: " + views : "")); switch (state) { case STATE_UI_TRANSLATION_STARTED: final Pair<TranslationSpec, TranslationSpec> specs = @@ -149,8 +157,69 @@ public class UiTranslationController { translator.dump(outerPrefix, pw); pw.println(); } + synchronized (mLock) { + final int viewSize = mViews.size(); + pw.print(outerPrefix); pw.print("number views: "); pw.println(viewSize); + for (int i = 0; i < viewSize; i++) { + pw.print(outerPrefix); pw.print("#"); pw.println(i); + final AutofillId autofillId = mViews.keyAt(i); + final View view = mViews.valueAt(i).get(); + pw.print(pfx); pw.print("autofillId: "); pw.println(autofillId); + pw.print(pfx); pw.print("view:"); pw.println(view); + } + } + // TODO(b/182433547): we will remove debug rom condition before S release then we change + // change this back to "DEBUG" + if (Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG)) { + dumpViewByTraversal(outerPrefix, pw); + } + } + + private void dumpViewByTraversal(String outerPrefix, PrintWriter pw) { + final ArrayList<ViewRootImpl> roots = + WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken()); + pw.print(outerPrefix); pw.println("Dump views:"); + for (int rootNum = 0; rootNum < roots.size(); rootNum++) { + final View rootView = roots.get(rootNum).getView(); + if (rootView instanceof ViewGroup) { + dumpChildren((ViewGroup) rootView, outerPrefix, pw); + } else { + dumpViewInfo(rootView, outerPrefix, pw); + } + } + } + + private void dumpChildren(ViewGroup viewGroup, String outerPrefix, PrintWriter pw) { + final int childCount = viewGroup.getChildCount(); + for (int i = 0; i < childCount; ++i) { + final View child = viewGroup.getChildAt(i); + if (child instanceof ViewGroup) { + pw.print(outerPrefix); pw.println("Children: "); + pw.print(outerPrefix); pw.print(outerPrefix); pw.println(child); + dumpChildren((ViewGroup) child, outerPrefix, pw); + } else { + pw.print(outerPrefix); pw.println("End Children: "); + pw.print(outerPrefix); pw.print(outerPrefix); pw.print(child); + dumpViewInfo(child, outerPrefix, pw); + } + } } + private void dumpViewInfo(View view, String outerPrefix, PrintWriter pw) { + final AutofillId autofillId = view.getAutofillId(); + pw.print(outerPrefix); pw.print("autofillId: "); pw.print(autofillId); + // TODO: print TranslationTransformation + boolean isContainsView = false; + synchronized (mLock) { + final WeakReference<View> viewRef = mViews.get(autofillId); + if (viewRef != null && viewRef.get() != null) { + isContainsView = true; + } + } + pw.print(outerPrefix); pw.print("isContainsView: "); pw.println(isContainsView); + } + + /** * The method is used by {@link Translator}, it will be called when the translation is done. The * translation result can be get from here. @@ -171,6 +240,9 @@ public class UiTranslationController { return; } final int resultCount = translatedResult.size(); + if (DEBUG) { + Log.v(TAG, "onTranslationCompleted: receive " + resultCount + " responses."); + } synchronized (mLock) { for (int i = 0; i < resultCount; i++) { final ViewTranslationResponse response = translatedResult.get(i); @@ -180,7 +252,7 @@ public class UiTranslationController { } final View view = mViews.get(autofillId).get(); if (view == null) { - Log.w(TAG, "onTranslationCompleted: the Veiew for autofill id " + autofillId + Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId + " may be gone."); continue; } @@ -208,6 +280,10 @@ public class UiTranslationController { @WorkerThread private void sendTranslationRequest(Translator translator, List<ViewTranslationRequest> requests) { + if (requests.size() == 0) { + Log.wtf(TAG, "No ViewTranslationRequest was collected."); + return; + } final TranslationRequest request = new TranslationRequest.Builder() .setViewTranslationRequests(requests) .build(); @@ -233,7 +309,8 @@ public class UiTranslationController { requests.add(request); } if (currentCount == (foundViews.size() - 1)) { - Log.v(TAG, "onUiTranslationStarted: send " + requests.size() + " request."); + Log.v(TAG, "onUiTranslationStarted: collect " + requests.size() + + " requests."); mWorkerHandler.sendMessage(PooledLambda.obtainMessage( UiTranslationController::sendTranslationRequest, UiTranslationController.this, translator, requests)); @@ -287,6 +364,9 @@ public class UiTranslationController { for (int i = 0; i < viewCounts; i++) { final View view = views.valueAt(i).get(); if (view == null) { + if (DEBUG) { + Log.d(TAG, "View was gone for autofillid = " + views.keyAt(i)); + } continue; } action.accept(view); diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java index a3a6a2e52138..7c73e701b7c8 100644 --- a/core/java/android/view/translation/UiTranslationManager.java +++ b/core/java/android/view/translation/UiTranslationManager.java @@ -43,6 +43,14 @@ public final class UiTranslationManager { private static final String TAG = "UiTranslationManager"; /** + * The tag which uses for enabling debug log dump. To enable it, we can use command "adb shell + * setprop log.tag.UiTranslation DEBUG". + * + * @hide + */ + public static final String LOG_TAG = "UiTranslation"; + + /** * The state caller request to disable utranslation,, it is no longer need to ui translation. * * @hide diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java index 34fe51e82e8f..42d75353e5df 100644 --- a/core/java/android/widget/AnalogClock.java +++ b/core/java/android/widget/AnalogClock.java @@ -200,6 +200,8 @@ public class AnalogClock extends View { mTimeZone = toZoneId(a.getString(com.android.internal.R.styleable.AnalogClock_timeZone)); createClock(); + a.recycle(); + mDialWidth = mDial.getIntrinsicWidth(); mDialHeight = mDial.getIntrinsicHeight(); } diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index dc42ad583543..45352e4d5ba2 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -20,6 +20,9 @@ import android.annotation.ColorInt; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; @@ -58,6 +61,29 @@ import java.lang.annotation.RetentionPolicy; * {@link #draw(Canvas)} method.</p> */ public class EdgeEffect { + /** + * This sets the default value for {@link #setType(int)} to {@link #TYPE_STRETCH} instead + * of {@link #TYPE_GLOW}. The type can still be overridden by the theme, view attribute, + * or by calling {@link #setType(int)}. + * + * @hide + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S) + public static final long USE_STRETCH_EDGE_EFFECT_BY_DEFAULT = 171228096L; + + /** + * This sets the default value for {@link #setType(int)} to {@link #TYPE_STRETCH} instead + * of {@link #TYPE_GLOW} for views that instantiate with + * {@link #EdgeEffect(Context, AttributeSet)}, indicating use of S+ EdgeEffect support. The + * type can still be overridden by the theme, view attribute, or by calling + * {@link #setType(int)}. + * + * @hide + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S) + public static final long USE_STRETCH_EDGE_EFFECT_FOR_SUPPORTED = 178807038L; /** * The default blend mode used by {@link EdgeEffect}. @@ -76,6 +102,28 @@ public class EdgeEffect { */ public static final int TYPE_STRETCH = 1; + /** + * The velocity threshold before the spring animation is considered settled. + * The idea here is that velocity should be less than 1 pixel per frame (~16ms). + */ + private static final double VELOCITY_THRESHOLD = 1.0 / 0.016; + + /** + * The value threshold before the spring animation is considered close enough to + * the destination to be settled. This should be around 1 pixel. + */ + private static final double VALUE_THRESHOLD = 1; + + /** + * The natural frequency of the stretch spring. + */ + private static final double NATURAL_FREQUENCY = 14.4222; + + /** + * The damping ratio of the stretch spring. + */ + private static final double DAMPING_RATIO = 0.875; + /** @hide */ @IntDef({TYPE_GLOW, TYPE_STRETCH}) @Retention(RetentionPolicy.SOURCE) @@ -119,20 +167,19 @@ public class EdgeEffect { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private float mGlowScaleY; private float mDistance; + private float mVelocity; // only for stretch animations private float mGlowAlphaStart; private float mGlowAlphaFinish; private float mGlowScaleYStart; private float mGlowScaleYFinish; - private float mDistanceStart; - private float mDistanceFinish; private long mStartTime; private float mDuration; private float mStretchIntensity = DEFAULT_MAX_STRETCH_INTENSITY; private float mStretchDistance = -1f; - private final Interpolator mInterpolator; + private final Interpolator mInterpolator = new DecelerateInterpolator(); private static final int STATE_IDLE = 0; private static final int STATE_PULL = 1; @@ -166,7 +213,7 @@ public class EdgeEffect { * @param context Context used to provide theming and resource information for the EdgeEffect */ public EdgeEffect(Context context) { - this(context, null); + this(context, null, Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_BY_DEFAULT)); } /** @@ -175,18 +222,26 @@ public class EdgeEffect { * @param attrs The attributes of the XML tag that is inflating the view */ public EdgeEffect(@NonNull Context context, @Nullable AttributeSet attrs) { - mPaint.setAntiAlias(true); + this(context, attrs, + Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_BY_DEFAULT) + || Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_FOR_SUPPORTED)); + } + + private EdgeEffect(@NonNull Context context, @Nullable AttributeSet attrs, + boolean defaultStretch) { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.EdgeEffect); final int themeColor = a.getColor( com.android.internal.R.styleable.EdgeEffect_colorEdgeEffect, 0xff666666); mEdgeEffectType = a.getInt( - com.android.internal.R.styleable.EdgeEffect_edgeEffectType, TYPE_GLOW); + com.android.internal.R.styleable.EdgeEffect_edgeEffectType, + defaultStretch ? TYPE_STRETCH : TYPE_GLOW); a.recycle(); + + mPaint.setAntiAlias(true); mPaint.setColor((themeColor & 0xffffff) | 0x33000000); mPaint.setStyle(Paint.Style.FILL); mPaint.setBlendMode(DEFAULT_BLEND_MODE); - mInterpolator = new DecelerateInterpolator(); } /** @@ -239,6 +294,8 @@ public class EdgeEffect { */ public void finish() { mState = STATE_IDLE; + mDistance = 0; + mVelocity = 0; } /** @@ -293,7 +350,8 @@ public class EdgeEffect { mDuration = PULL_TIME; mPullDistance += deltaDistance; - mDistanceStart = mDistanceFinish = mDistance = Math.max(0f, mPullDistance); + mDistance = Math.max(0f, mPullDistance); + mVelocity = 0; final float absdd = Math.abs(deltaDistance); mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA, @@ -387,11 +445,10 @@ public class EdgeEffect { mState = STATE_RECEDE; mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; - mDistanceStart = mDistance; mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; - mDistanceFinish = 0.f; + mVelocity = 0.f; mStartTime = AnimationUtils.currentAnimationTimeMillis(); mDuration = RECEDE_TIME; @@ -408,30 +465,36 @@ public class EdgeEffect { * @param velocity Velocity at impact in pixels per second. */ public void onAbsorb(int velocity) { - mState = STATE_ABSORB; - velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY); - - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mDuration = 0.15f + (velocity * 0.02f); - - // The glow depends more on the velocity, and therefore starts out - // nearly invisible. - mGlowAlphaStart = GLOW_ALPHA_START; - mGlowScaleYStart = Math.max(mGlowScaleY, 0.f); - mDistanceStart = mDistance; - - // Growth for the size of the glow should be quadratic to properly - // respond - // to a user's scrolling speed. The faster the scrolling speed, the more - // intense the effect should be for both the size and the saturation. - mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f); - // Alpha should change for the glow as well as size. - mGlowAlphaFinish = Math.max( - mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); - mTargetDisplacement = 0.5f; - - // Use glow values to estimate the absorption for stretch distance. - mDistanceFinish = calculateDistanceFromGlowValues(mGlowScaleYFinish, mGlowAlphaFinish); + if (mEdgeEffectType == TYPE_STRETCH) { + mState = STATE_RECEDE; + mVelocity = velocity / mHeight; + mDistance = 0; + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + } else { + mState = STATE_ABSORB; + mVelocity = 0; + velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY); + + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + mDuration = 0.15f + (velocity * 0.02f); + + // The glow depends more on the velocity, and therefore starts out + // nearly invisible. + mGlowAlphaStart = GLOW_ALPHA_START; + mGlowScaleYStart = Math.max(mGlowScaleY, 0.f); + + // Growth for the size of the glow should be quadratic to properly + // respond + // to a user's scrolling speed. The faster the scrolling speed, the more + // intense the effect should be for both the size and the saturation. + mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, + 1.f); + // Alpha should change for the glow as well as size. + mGlowAlphaFinish = Math.max( + mGlowAlphaStart, + Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); + mTargetDisplacement = 0.5f; + } } /** @@ -539,8 +602,8 @@ public class EdgeEffect { canvas.drawCircle(centerX, centerY, mRadius, mPaint); canvas.restoreToCount(count); } else if (canvas instanceof RecordingCanvas) { - if (mState != STATE_PULL) { - update(); + if (mState == STATE_RECEDE) { + updateSpring(); } RecordingCanvas recordingCanvas = (RecordingCanvas) canvas; if (mTmpMatrix == null) { @@ -597,7 +660,7 @@ public class EdgeEffect { } boolean oneLastFrame = false; - if (mState == STATE_RECEDE && mDistance == 0) { + if (mState == STATE_RECEDE && mDistance == 0 && mVelocity == 0) { mState = STATE_IDLE; oneLastFrame = true; } @@ -634,7 +697,7 @@ public class EdgeEffect { mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp; mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp; - mDistance = mDistanceStart + (mDistanceFinish - mDistanceStart) * interp; + mDistance = calculateDistanceFromGlowValues(mGlowScaleY, mGlowAlpha); mDisplacement = (mDisplacement + mTargetDisplacement) / 2; if (t >= 1.f - EPSILON) { @@ -646,12 +709,10 @@ public class EdgeEffect { mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; - mDistanceStart = mDistance; // After absorb, the glow should fade to nothing. mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; - mDistanceFinish = 0.f; break; case STATE_PULL: mState = STATE_PULL_DECAY; @@ -660,12 +721,10 @@ public class EdgeEffect { mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; - mDistanceStart = mDistance; // After pull, the glow should fade to nothing. mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; - mDistanceFinish = 0.f; break; case STATE_PULL_DECAY: mState = STATE_RECEDE; @@ -677,6 +736,35 @@ public class EdgeEffect { } } + private void updateSpring() { + final long time = AnimationUtils.currentAnimationTimeMillis(); + final float deltaT = (time - mStartTime) / 1000f; // Convert from millis to seconds + if (deltaT < 0.001f) { + return; // Must have at least 1 ms difference + } + final double mDampedFreq = NATURAL_FREQUENCY * Math.sqrt(1 - DAMPING_RATIO * DAMPING_RATIO); + + // We're always underdamped, so we can use only those equations: + double cosCoeff = mDistance; + double sinCoeff = (1 / mDampedFreq) * (DAMPING_RATIO * NATURAL_FREQUENCY + * mDistance + mVelocity); + double distance = Math.pow(Math.E, -DAMPING_RATIO * NATURAL_FREQUENCY * deltaT) + * (cosCoeff * Math.cos(mDampedFreq * deltaT) + + sinCoeff * Math.sin(mDampedFreq * deltaT)); + double velocity = distance * (-NATURAL_FREQUENCY) * DAMPING_RATIO + + Math.pow(Math.E, -DAMPING_RATIO * NATURAL_FREQUENCY * deltaT) + * (-mDampedFreq * cosCoeff * Math.sin(mDampedFreq * deltaT) + + mDampedFreq * sinCoeff * Math.cos(mDampedFreq * deltaT)); + mDistance = (float) distance; + mVelocity = (float) velocity; + mStartTime = time; + if (isAtEquilibrium()) { + mState = STATE_IDLE; + mDistance = 0; + mVelocity = 0; + } + } + /** * @return The estimated pull distance as calculated from mGlowScaleY. */ @@ -692,4 +780,15 @@ public class EdgeEffect { } return alpha / PULL_DISTANCE_ALPHA_GLOW_FACTOR; } + + /** + * @return true if the spring used for calculating the stretch animation is + * considered at rest or false if it is still animating. + */ + private boolean isAtEquilibrium() { + double velocity = mVelocity * mHeight; // in pixels/second + double displacement = mDistance * mHeight; // in pixels + return Math.abs(velocity) < VELOCITY_THRESHOLD + && Math.abs(displacement) < VALUE_THRESHOLD; + } } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 012352d0a0f5..7517b805da69 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -3790,7 +3790,7 @@ public class Editor { } public SuggestionsPopupWindow() { - mCursorWasVisibleBeforeSuggestions = mCursorVisible; + mCursorWasVisibleBeforeSuggestions = mTextView.isCursorVisibleFromAttr(); } @Override @@ -3957,7 +3957,7 @@ public class Editor { } if (updateSuggestions()) { - mCursorWasVisibleBeforeSuggestions = mCursorVisible; + mCursorWasVisibleBeforeSuggestions = mTextView.isCursorVisibleFromAttr(); mTextView.setCursorVisible(false); mIsShowingUp = true; super.show(); diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 2328e589216b..d2f4cea69c88 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -120,6 +120,7 @@ import java.util.Objects; import java.util.Stack; import java.util.concurrent.Executor; import java.util.function.Consumer; +import java.util.function.Predicate; /** * A class that describes a view hierarchy that can be displayed in @@ -1993,22 +1994,79 @@ public class RemoteViews implements Parcelable, Filter { mIsRoot = false; } + private static boolean hasStableId(View view) { + Object tag = view.getTag(com.android.internal.R.id.remote_views_stable_id); + return tag != null; + } + + private static int getStableId(View view) { + Integer id = (Integer) view.getTag(com.android.internal.R.id.remote_views_stable_id); + return id == null ? ViewGroupActionAdd.NO_ID : id; + } + + private static void setStableId(View view, int stableId) { + view.setTagInternal(com.android.internal.R.id.remote_views_stable_id, stableId); + } + + // Returns the next recyclable child of the view group, or -1 if there are none. + private static int getNextRecyclableChild(ViewGroup vg) { + Integer tag = (Integer) vg.getTag(com.android.internal.R.id.remote_views_next_child); + return tag == null ? -1 : tag; + } + + private static int getViewLayoutId(View v) { + return (Integer) v.getTag(R.id.widget_frame); + } + + private static void setNextRecyclableChild(ViewGroup vg, int nextChild, int numChildren) { + if (nextChild < 0 || nextChild >= numChildren) { + vg.setTagInternal(com.android.internal.R.id.remote_views_next_child, -1); + } else { + vg.setTagInternal(com.android.internal.R.id.remote_views_next_child, nextChild); + } + } + + private void finalizeViewRecycling(ViewGroup root) { + // Remove any recyclable children that were not used. nextChild should either be -1 or point + // to the next recyclable child that hasn't been recycled. + int nextChild = getNextRecyclableChild(root); + if (nextChild >= 0 && nextChild < root.getChildCount()) { + root.removeViews(nextChild, root.getChildCount() - nextChild); + } + // Make sure on the next round, we don't try to recycle if removeAllViews is not called. + setNextRecyclableChild(root, -1, 0); + // Traverse the view tree. + for (int i = 0; i < root.getChildCount(); i++) { + View child = root.getChildAt(i); + if (child instanceof ViewGroup && !child.isRootNamespace()) { + finalizeViewRecycling((ViewGroup) child); + } + } + } + /** * ViewGroup methods that are related to adding Views. */ private class ViewGroupActionAdd extends Action { + static final int NO_ID = -1; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private RemoteViews mNestedViews; private int mIndex; + private int mStableId; ViewGroupActionAdd(@IdRes int viewId, RemoteViews nestedViews) { - this(viewId, nestedViews, -1 /* index */); + this(viewId, nestedViews, -1 /* index */, NO_ID /* nestedViewId */); } ViewGroupActionAdd(@IdRes int viewId, RemoteViews nestedViews, int index) { + this(viewId, nestedViews, index, NO_ID /* nestedViewId */); + } + + ViewGroupActionAdd(@IdRes int viewId, RemoteViews nestedViews, int index, int stableId) { this.viewId = viewId; mNestedViews = nestedViews; mIndex = index; + mStableId = stableId; if (nestedViews != null) { configureRemoteViewsAsChild(nestedViews); } @@ -2018,6 +2076,7 @@ public class RemoteViews implements Parcelable, Filter { int depth, Map<Class, Object> classCookies) { viewId = parcel.readInt(); mIndex = parcel.readInt(); + mStableId = parcel.readInt(); mNestedViews = new RemoteViews(parcel, bitmapCache, info, depth, classCookies); mNestedViews.addFlags(mApplyFlags); } @@ -2025,6 +2084,7 @@ public class RemoteViews implements Parcelable, Filter { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(viewId); dest.writeInt(mIndex); + dest.writeInt(mStableId); mNestedViews.writeToParcel(dest, flags); } @@ -2033,6 +2093,17 @@ public class RemoteViews implements Parcelable, Filter { return mNestedViews.hasSameAppInfo(parentInfo); } + private int findViewIndexToRecycle(ViewGroup target, RemoteViews newContent) { + for (int nextChild = getNextRecyclableChild(target); nextChild < target.getChildCount(); + nextChild++) { + View child = target.getChildAt(nextChild); + if (getStableId(child) == mStableId) { + return nextChild; + } + } + return -1; + } + @Override public void apply(View root, ViewGroup rootParent, InteractionHandler handler, ColorResources colorResources) { @@ -2043,10 +2114,45 @@ public class RemoteViews implements Parcelable, Filter { return; } + // If removeAllViews was called, this returns the next potential recycled view. + // If there are no more views to recycle (or removeAllViews was not called), this + // will return -1. + final int nextChild = getNextRecyclableChild(target); + RemoteViews rvToApply = mNestedViews.getRemoteViewsToApply(context); + if (nextChild >= 0 && mStableId != NO_ID) { + // At that point, the views starting at index nextChild are the ones recyclable but + // not yet recycled. All views added on that round of application are placed before. + // Find the next view with the same stable id, or -1. + int recycledViewIndex = findViewIndexToRecycle(target, rvToApply); + if (recycledViewIndex >= 0) { + View child = target.getChildAt(recycledViewIndex); + if (getViewLayoutId(child) == rvToApply.getLayoutId()) { + if (nextChild < recycledViewIndex) { + target.removeViews(nextChild, recycledViewIndex - nextChild); + } + setNextRecyclableChild(target, nextChild + 1, target.getChildCount()); + rvToApply.reapply(context, child, handler, null /* size */, colorResources, + false /* topLevel */); + return; + } + // If we cannot recycle the views, we still remove all views in between to + // avoid weird behaviors and insert the new view in place of the old one. + target.removeViews(nextChild, recycledViewIndex - nextChild + 1); + } + } + // If we cannot recycle, insert the new view before the next recyclable child. + // Inflate nested views and add as children - target.addView( - mNestedViews.apply(context, target, handler, null /* size */, colorResources), - mIndex); + View nestedView = rvToApply.apply(context, target, handler, null /* size */, + colorResources); + if (mStableId != NO_ID) { + setStableId(nestedView, mStableId); + } + target.addView(nestedView, mIndex >= 0 ? mIndex : nextChild); + if (nextChild >= 0) { + // If we are at the end, there is no reason to try to recycle anymore + setNextRecyclableChild(target, nextChild + 1, target.getChildCount()); + } } @Override @@ -2063,24 +2169,91 @@ public class RemoteViews implements Parcelable, Filter { // Inflate nested views and perform all the async tasks for the child remoteView. final Context context = root.mRoot.getContext(); - final AsyncApplyTask task = mNestedViews.getAsyncApplyTask(context, targetVg, - null /* listener */, handler, null /* size */, colorResources); + + // If removeAllViews was called, this returns the next potential recycled view. + // If there are no more views to recycle (or removeAllViews was not called), this + // will return -1. + final int nextChild = getNextRecyclableChild(targetVg); + if (nextChild >= 0 && mStableId != NO_ID) { + RemoteViews rvToApply = mNestedViews.getRemoteViewsToApply(context); + final int recycledViewIndex = target.findChildIndex(nextChild, + view -> getStableId(view) == mStableId); + if (recycledViewIndex >= 0) { + // At that point, the views starting at index nextChild are the ones + // recyclable but not yet recycled. All views added on that round of + // application are placed before. + ViewTree recycled = target.mChildren.get(recycledViewIndex); + // We can only recycle the view if the layout id is the same. + if (getViewLayoutId(recycled.mRoot) == rvToApply.getLayoutId()) { + if (recycledViewIndex > nextChild) { + target.removeChildren(nextChild, recycledViewIndex - nextChild); + } + setNextRecyclableChild(targetVg, nextChild + 1, target.mChildren.size()); + final AsyncApplyTask reapplyTask = rvToApply.getInternalAsyncApplyTask( + context, + targetVg, null /* listener */, handler, null /* size */, + colorResources, + recycled.mRoot); + final ViewTree tree = reapplyTask.doInBackground(); + if (tree == null) { + throw new ActionException(reapplyTask.mError); + } + return new RuntimeAction() { + @Override + public void apply(View root, ViewGroup rootParent, + InteractionHandler handler, ColorResources colorResources) + throws ActionException { + reapplyTask.onPostExecute(tree); + if (recycledViewIndex > nextChild) { + targetVg.removeViews(nextChild, recycledViewIndex - nextChild); + } + } + }; + } + // If the layout id is different, still remove the children as if we recycled + // the view, to insert at the same place. + target.removeChildren(nextChild, recycledViewIndex - nextChild + 1); + return insertNewView(context, target, handler, colorResources, + () -> targetVg.removeViews(nextChild, + recycledViewIndex - nextChild + 1)); + + } + } + // If we cannot recycle, simply add the view at the same available slot. + return insertNewView(context, target, handler, colorResources, () -> {}); + } + + private Action insertNewView(Context context, ViewTree target, InteractionHandler handler, + ColorResources colorResources, Runnable finalizeAction) { + ViewGroup targetVg = (ViewGroup) target.mRoot; + int nextChild = getNextRecyclableChild(targetVg); + final AsyncApplyTask task = mNestedViews.getInternalAsyncApplyTask(context, targetVg, + null /* listener */, handler, null /* size */, colorResources, + null /* result */); final ViewTree tree = task.doInBackground(); if (tree == null) { throw new ActionException(task.mError); } + if (mStableId != NO_ID) { + setStableId(task.mResult, mStableId); + } // Update the global view tree, so that next call to findViewTreeById // goes through the subtree as well. - target.addChild(tree, mIndex); + final int insertIndex = mIndex >= 0 ? mIndex : nextChild; + target.addChild(tree, insertIndex); + if (nextChild >= 0) { + setNextRecyclableChild(targetVg, nextChild + 1, target.mChildren.size()); + } return new RuntimeAction() { @Override public void apply(View root, ViewGroup rootParent, InteractionHandler handler, ColorResources colorResources) throws ActionException { task.onPostExecute(tree); - targetVg.addView(task.mResult, mIndex); + finalizeAction.run(); + targetVg.addView(task.mResult, insertIndex); } }; } @@ -2148,7 +2321,14 @@ public class RemoteViews implements Parcelable, Filter { } if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) { - target.removeAllViews(); + // Remote any view without a stable id + for (int i = target.getChildCount() - 1; i >= 0; i--) { + if (!hasStableId(target.getChildAt(i))) { + target.removeViewAt(i); + } + } + // In the end, only children with a stable id (i.e. recyclable) are left. + setNextRecyclableChild(target, 0, target.getChildCount()); return; } @@ -2170,8 +2350,8 @@ public class RemoteViews implements Parcelable, Filter { final ViewGroup targetVg = (ViewGroup) target.mRoot; if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) { - // Clear all children when there's no excepted view - target.mChildren = null; + target.mChildren.removeIf(childTree -> !hasStableId(childTree.mRoot)); + setNextRecyclableChild(targetVg, 0, target.mChildren.size()); } else { // Remove just the children which don't match the excepted view target.mChildren.removeIf(childTree -> childTree.mRoot.getId() != mViewIdToKeep); @@ -2184,7 +2364,11 @@ public class RemoteViews implements Parcelable, Filter { public void apply(View root, ViewGroup rootParent, InteractionHandler handler, ColorResources colorResources) throws ActionException { if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) { - targetVg.removeAllViews(); + for (int i = targetVg.getChildCount() - 1; i >= 0; i--) { + if (!hasStableId(targetVg.getChildAt(i))) { + targetVg.removeViewAt(i); + } + } return; } @@ -3084,6 +3268,7 @@ public class RemoteViews implements Parcelable, Filter { } mApplication = portrait.mApplication; mLayoutId = portrait.mLayoutId; + mViewId = portrait.mViewId; mLightBackgroundLayoutId = portrait.mLightBackgroundLayoutId; mLandscape = landscape; @@ -3136,6 +3321,7 @@ public class RemoteViews implements Parcelable, Filter { RemoteViews smallestView = findSmallestRemoteView(); mApplication = smallestView.mApplication; mLayoutId = smallestView.mLayoutId; + mViewId = smallestView.mViewId; mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId; } @@ -3253,6 +3439,7 @@ public class RemoteViews implements Parcelable, Filter { ApplicationInfo.CREATOR.createFromParcel(parcel); mIdealSize = parcel.readInt() == 0 ? null : SizeF.CREATOR.createFromParcel(parcel); mLayoutId = parcel.readInt(); + mViewId = parcel.readInt(); mLightBackgroundLayoutId = parcel.readInt(); readActionsFromParcel(parcel, depth); @@ -3273,6 +3460,7 @@ public class RemoteViews implements Parcelable, Filter { RemoteViews smallestView = findSmallestRemoteView(); mApplication = smallestView.mApplication; mLayoutId = smallestView.mLayoutId; + mViewId = smallestView.mViewId; mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId; } else { // MODE_HAS_LANDSCAPE_AND_PORTRAIT @@ -3281,6 +3469,7 @@ public class RemoteViews implements Parcelable, Filter { mClassCookies); mApplication = mPortrait.mApplication; mLayoutId = mPortrait.mLayoutId; + mViewId = mPortrait.mViewId; mLightBackgroundLayoutId = mPortrait.mLightBackgroundLayoutId; } mApplyFlags = parcel.readInt(); @@ -3458,6 +3647,29 @@ public class RemoteViews implements Parcelable, Filter { } /** + * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the given + * {@link RemoteViews}. If the {@link RemoteViews} may be re-inflated or updated, + * {@link #removeAllViews(int)} must be called on the same {@code viewId + * } before the first call to this method for the behavior of this method to be predictable. + * + * The {@code stableId} will be used to identify a potential view to recycled when the remote + * view is inflated. Views can be re-used if inserted in the same order, potentially with + * some views appearing / disappearing. + * + * Note: if a view is re-used, all the actions will be re-applied on it. However, its properties + * are not reset, so what was applied in previous round will have an effect. As a view may be + * re-created at any time by the host, the RemoteViews should not rely on keeping information + * from previous applications and always re-set all the properties they need. + * + * @param viewId The id of the parent {@link ViewGroup} to add child into. + * @param nestedView {@link RemoteViews} that describes the child. + * @param stableId An id that is stable across different versions of RemoteViews. + */ + public void addStableView(@IdRes int viewId, @NonNull RemoteViews nestedView, int stableId) { + addAction(new ViewGroupActionAdd(viewId, nestedView, -1 /* index */, stableId)); + } + + /** * Equivalent to calling {@link ViewGroup#addView(View, int)} after inflating the * given {@link RemoteViews}. * @@ -4870,23 +5082,24 @@ public class RemoteViews implements Parcelable, Filter { public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener, InteractionHandler handler, SizeF size) { - return getAsyncApplyTask(context, parent, listener, handler, size, null /* themeColors */) - .startTaskOnExecutor(executor); + return applyAsync(context, parent, executor, listener, handler, size, + null /* themeColors */); } /** @hide */ public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener, InteractionHandler handler, SizeF size, ColorResources colorResources) { - return getAsyncApplyTask(context, parent, listener, handler, size, colorResources) - .startTaskOnExecutor(executor); + return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener, + handler, colorResources, null /* result */, + true /* topLevel */).startTaskOnExecutor(executor); } - private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent, + private AsyncApplyTask getInternalAsyncApplyTask(Context context, ViewGroup parent, OnViewAppliedListener listener, InteractionHandler handler, SizeF size, - ColorResources colorResources) { + ColorResources colorResources, View result) { return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener, - handler, colorResources, null /* result */); + handler, colorResources, result, false /* topLevel */); } private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree> @@ -4898,6 +5111,12 @@ public class RemoteViews implements Parcelable, Filter { final OnViewAppliedListener mListener; final InteractionHandler mHandler; final ColorResources mColorResources; + /** + * Whether the remote view is the top-level one (i.e. not within an action). + * + * This is only used if the result is specified (i.e. the view is being recycled). + */ + final boolean mTopLevel; private View mResult; private ViewTree mTree; @@ -4906,13 +5125,15 @@ public class RemoteViews implements Parcelable, Filter { private AsyncApplyTask( RemoteViews rv, ViewGroup parent, Context context, OnViewAppliedListener listener, - InteractionHandler handler, ColorResources colorResources, View result) { + InteractionHandler handler, ColorResources colorResources, + View result, boolean topLevel) { mRV = rv; mParent = parent; mContext = context; mListener = listener; mColorResources = colorResources; mHandler = handler; + mTopLevel = topLevel; mResult = result; } @@ -4959,6 +5180,10 @@ public class RemoteViews implements Parcelable, Filter { a.apply(viewTree.mRoot, mParent, handler, mColorResources); } } + // If the parent of the view is has is a root, resolve the recycling. + if (mTopLevel && mResult instanceof ViewGroup) { + finalizeViewRecycling((ViewGroup) mResult); + } } catch (Exception e) { mError = e; } @@ -5011,6 +5236,14 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public void reapply(Context context, View v, InteractionHandler handler, SizeF size, ColorResources colorResources) { + reapply(context, v, handler, size, colorResources, true); + } + + // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls + // should set it to false. + private void reapply(Context context, View v, InteractionHandler handler, SizeF size, + ColorResources colorResources, boolean topLevel) { + RemoteViews rvToApply = getRemoteViewsToApply(context, size); // In the case that a view has this RemoteViews applied in one orientation or size, is @@ -5025,6 +5258,11 @@ public class RemoteViews implements Parcelable, Filter { } rvToApply.performApply(v, (ViewGroup) v.getParent(), handler, colorResources); + + // If the parent of the view is has is a root, resolve the recycling. + if (topLevel && v instanceof ViewGroup) { + finalizeViewRecycling((ViewGroup) v); + } } /** @@ -5068,8 +5306,8 @@ public class RemoteViews implements Parcelable, Filter { } return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(), - context, listener, handler, colorResources, v).startTaskOnExecutor( - executor); + context, listener, handler, colorResources, v, true /* topLevel */) + .startTaskOnExecutor(executor); } private void performApply(View v, ViewGroup parent, InteractionHandler handler, @@ -5282,6 +5520,7 @@ public class RemoteViews implements Parcelable, Filter { mIdealSize.writeToParcel(dest, flags); } dest.writeInt(mLayoutId); + dest.writeInt(mViewId); dest.writeInt(mLightBackgroundLayoutId); writeActionsToParcel(dest); } else if (hasSizedRemoteViews()) { @@ -5470,6 +5709,14 @@ public class RemoteViews implements Parcelable, Filter { mChildren.add(index, child); } + public void removeChildren(int start, int count) { + if (mChildren != null) { + for (int i = 0; i < count; i++) { + mChildren.remove(start); + } + } + } + private void addViewChild(View v) { // ViewTree only contains Views which can be found using findViewById. // If isRootNamespace is true, this view is skipped. @@ -5500,6 +5747,28 @@ public class RemoteViews implements Parcelable, Filter { } } } + + /** Find the first child for which the condition is true and return its index. */ + public int findChildIndex(Predicate<View> condition) { + return findChildIndex(0, condition); + } + + /** + * Find the first child, starting at {@code startIndex}, for which the condition is true and + * return its index. + */ + public int findChildIndex(int startIndex, Predicate<View> condition) { + if (mChildren == null) { + return -1; + } + + for (int i = startIndex; i < mChildren.size(); i++) { + if (condition.test(mChildren.get(i).mRoot)) { + return i; + } + } + return -1; + } } /** @@ -5758,9 +6027,9 @@ public class RemoteViews implements Parcelable, Filter { } /** - * Set the ID of the top-level view of the XML layout. + * Set the ID of the top-level view of the XML layout. * - * Set to {@link View#NO_ID} to reset and simply keep the id defined in the XML layout. + * Set to {@link View#NO_ID} to reset and simply keep the id defined in the XML layout. * * @throws UnsupportedOperationException if the method is called on a RemoteViews defined in * term of other RemoteViews (e.g. {@link #RemoteViews(RemoteViews, RemoteViews)}). diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index fdc66fcb81d8..dba7fa915f35 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -195,6 +195,7 @@ import android.view.textclassifier.TextLinks; import android.view.textservice.SpellCheckerSubtype; import android.view.textservice.TextServicesManager; import android.view.translation.TranslationRequestValue; +import android.view.translation.UiTranslationController; import android.view.translation.ViewTranslationRequest; import android.view.translation.ViewTranslationResponse; import android.widget.RemoteViews.RemoteView; @@ -502,7 +503,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private boolean mImeIsConsumingInput; // Whether cursor is visible without regard to {@link mImeConsumesInput}. - // {code true} is the default value. + // {@code true} is the default value. private boolean mCursorVisibleFromAttr = true; static class Drawables { @@ -9316,7 +9317,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } for (int i = 0; i < n; i++) { - max = Math.max(max, layout.getLineWidth(i)); + max = Math.max(max, layout.getLineMax(i)); } return (int) Math.ceil(max); @@ -10570,6 +10571,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mEditor == null ? true : mEditor.mCursorVisible; } + /** + * @return whether cursor is visible without regard to {@code mImeIsConsumingInput}. + * {@code true} is the default value. + * + * @see #setCursorVisible(boolean) + * @hide + */ + public boolean isCursorVisibleFromAttr() { + return mCursorVisibleFromAttr; + } + private boolean canMarquee() { int width = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight(); return width > 0 && (mLayout.getLineWidth(0) > width @@ -13835,6 +13847,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public ViewTranslationRequest onCreateTranslationRequest() { if (mText == null || mText.length() == 0) { + // TODO(b/182433547): remove before S release + if (UiTranslationController.DEBUG) { + Log.w(LOG_TAG, "Cannot create translation request for the empty text."); + } return null; } // Not translate password, editable text and not important for translation @@ -13842,6 +13858,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // text selection apis, not support in S. boolean isPassword = isAnyPasswordInputType() || hasPasswordTransformationMethod(); if (isTextEditable() || isPassword || isTextSelectable()) { + // TODO(b/182433547): remove before S release + if (UiTranslationController.DEBUG) { + Log.w(LOG_TAG, "Cannot create translation request. editable = " + isTextEditable() + + ", isPassword = " + isPassword + ", selectable = " + isTextSelectable()); + } return null; } // TODO(b/176488462): apply the view's important for translation property @@ -13870,6 +13891,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Restore to original text content. if (mTranslationTransformation != null) { setTransformationMethod(mTranslationTransformation.getOriginalTransformationMethod()); + } else { + // TODO(b/182433547): remove before S release + Log.w(LOG_TAG, "onPauseUiTranslation(): no translated text."); } } @@ -13889,7 +13913,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mTranslationTransformation != null) { setTransformationMethod(mTranslationTransformation); } else { - Log.w(LOG_TAG, "onResumeTranslatedText(): no translated text."); + // TODO(b/182433547): remove before S release + Log.w(LOG_TAG, "onRestoreUiTranslation(): no translated text."); } } @@ -13910,6 +13935,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mTranslationTransformation != null) { setTransformationMethod(mTranslationTransformation.getOriginalTransformationMethod()); mTranslationTransformation = null; + } else { + // TODO(b/182433547): remove before S release + Log.w(LOG_TAG, "onFinishUiTranslation(): no translated text."); } } diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl index 8f541d0bd194..3eb35c2c5e8a 100644 --- a/core/java/android/window/ITaskOrganizer.aidl +++ b/core/java/android/window/ITaskOrganizer.aidl @@ -18,6 +18,7 @@ package android.window; import android.view.SurfaceControl; import android.app.ActivityManager; +import android.graphics.Rect; import android.window.StartingWindowInfo; import android.window.WindowContainerToken; @@ -38,8 +39,12 @@ oneway interface ITaskOrganizer { /** * Called when the Task want to remove the starting window. + * @param leash A persistent leash for the top window in this task. + * @param frame Window frame of the top window. + * @param playRevealAnimation Play vanish animation. */ - void removeStartingWindow(int taskId); + void removeStartingWindow(int taskId, in SurfaceControl leash, in Rect frame, + in boolean playRevealAnimation); /** * Called when the Task want to copy the splash screen. diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java index 35ccfca101d3..da445b8b9f33 100644 --- a/core/java/android/window/SplashScreenView.java +++ b/core/java/android/window/SplashScreenView.java @@ -46,6 +46,8 @@ import android.widget.FrameLayout; import com.android.internal.R; import com.android.internal.policy.DecorView; +import java.util.function.Consumer; + /** * <p>The view which allows an activity to customize its splash screen exit animation.</p> * @@ -77,7 +79,8 @@ public final class SplashScreenView extends FrameLayout { private Animatable mAnimatableIcon; private ValueAnimator mAnimator; - + private Runnable mAnimationFinishListener; + private Consumer<Canvas> mOnDrawCallback; // cache original window and status private Window mWindow; private boolean mDrawBarBackground; @@ -85,7 +88,7 @@ public final class SplashScreenView extends FrameLayout { private int mNavigationBarColor; /** - * Internal builder to create a SplashScreenWindowView object. + * Internal builder to create a SplashScreenView object. * @hide */ public static class Builder { @@ -391,7 +394,7 @@ public final class SplashScreenView extends FrameLayout { * Get the initial background color of this view. * @hide */ - @ColorInt int getInitBackgroundColor() { + public @ColorInt int getInitBackgroundColor() { return mInitBackgroundColor; } diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java index d1c1e40d1578..c7672dc9fe7d 100644 --- a/core/java/android/window/StartingWindowInfo.java +++ b/core/java/android/window/StartingWindowInfo.java @@ -126,6 +126,12 @@ public final class StartingWindowInfo implements Parcelable { */ public int splashScreenThemeResId; + /** + * Is keyguard occluded on default display. + * @hide + */ + public boolean isKeyguardOccluded = false; + public StartingWindowInfo() { } @@ -147,6 +153,7 @@ public final class StartingWindowInfo implements Parcelable { dest.writeTypedObject(topOpaqueWindowLayoutParams, flags); dest.writeTypedObject(mainWindowLayoutParams, flags); dest.writeInt(splashScreenThemeResId); + dest.writeBoolean(isKeyguardOccluded); } void readFromParcel(@NonNull Parcel source) { @@ -157,6 +164,7 @@ public final class StartingWindowInfo implements Parcelable { WindowManager.LayoutParams.CREATOR); mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR); splashScreenThemeResId = source.readInt(); + isKeyguardOccluded = source.readBoolean(); } @Override diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index 04020ec3ee8a..3340cf4fb707 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -24,6 +24,7 @@ import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.TestApi; import android.app.ActivityManager; +import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; import android.view.SurfaceControl; @@ -100,9 +101,14 @@ public class TaskOrganizer extends WindowOrganizer { /** * Called when the Task want to remove the starting window. + * @param leash A persistent leash for the top window in this task. Release it once exit + * animation has finished. + * @param frame Window frame of the top window. + * @param playRevealAnimation Play vanish animation. */ @BinderThread - public void removeStartingWindow(int taskId) {} + public void removeStartingWindow(int taskId, @Nullable SurfaceControl leash, + @Nullable Rect frame, boolean playRevealAnimation) {} /** * Called when the Task want to copy the splash screen. @@ -217,15 +223,16 @@ public class TaskOrganizer extends WindowOrganizer { private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() { @Override - public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) { mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo, appToken)); } @Override - public void removeStartingWindow(int taskId) { - mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId)); + public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { + mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId, leash, frame, + playRevealAnimation)); } @Override diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 6cfd49888fac..d4d853624700 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -1119,7 +1119,7 @@ public class ChooserActivity extends ResolverActivity implements ClipboardManager clipboardManager = (ClipboardManager) getSystemService( Context.CLIPBOARD_SERVICE); - clipboardManager.setPrimaryClip(clipData); + clipboardManager.setPrimaryClipAsPackage(clipData, getReferrerPackageName()); Toast.makeText(getApplicationContext(), R.string.copied, Toast.LENGTH_SHORT).show(); // Log share completion via copy diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index c1952c7d52cf..957e416986e0 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -166,4 +166,15 @@ interface IBatteryStats { /** {@hide} */ boolean setChargingStateUpdateDelayMillis(int delay); + + /** Exposed as a test API. */ + void setChargerAcOnline(boolean online, boolean forceUpdate); + /** Exposed as a test API. */ + void setBatteryLevel(int level, boolean forceUpdate); + /** Exposed as a test API. */ + void unplugBattery(boolean forceUpdate); + /** Exposed as a test API. */ + void resetBattery(boolean forceUpdate); + /** Exposed as a test API. */ + void suspendBatteryInput(); } diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index ccb980eb82b7..592f7c7e1925 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -21,6 +21,7 @@ import android.content.Intent; import android.media.permission.Identity; import android.os.Bundle; import android.os.RemoteCallback; +import android.os.SharedMemory; import com.android.internal.app.IVoiceActionCheckCallback; import com.android.internal.app.IVoiceInteractionSessionShowCallback; @@ -225,14 +226,19 @@ interface IVoiceInteractionManagerService { IBinder client); /** - * Sets hotword detection configuration. + * Set configuration and pass read-only data to hotword detection service. * - * Note: Currently it will trigger hotword detection service after calling this function when - * all conditions meet the requirements. - * - * @param options Config data. - * @return {@link VoiceInteractionService#HOTWORD_CONFIG_SUCCESS} in case of success, - * {@link VoiceInteractionService#HOTWORD_CONFIG_FAILURE} in case of failure. + * @param options Application configuration data provided by the + * {@link VoiceInteractionService}. The system strips out any remotable objects or other + * contents that can be used to communicate with other processes. + * @param sharedMemory The unrestricted data blob provided by the + * {@link VoiceInteractionService}. Use this to provide the hotword models data or other + * such data to the trusted process. + */ + void setHotwordDetectionServiceConfig(in Bundle options, in SharedMemory sharedMemory); + + /** + * Requests to shutdown hotword detection service. */ - int setHotwordDetectionConfig(in Bundle options); + void shutdownHotwordDetectionService(); } diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java index 0b937fad7df1..364db06976a0 100644 --- a/core/java/com/android/internal/compat/AndroidBuildClassifier.java +++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java @@ -31,4 +31,14 @@ public class AndroidBuildClassifier { public boolean isFinalBuild() { return "REL".equals(Build.VERSION.CODENAME); } + + /** + * The current platform SDK version. + */ + public int platformTargetSdk() { + if (isFinalBuild()) { + return Build.VERSION.SDK_INT; + } + return Build.VERSION_CODES.CUR_DEVELOPMENT; + } } diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java index c0bbe5082131..e408be2ab471 100644 --- a/core/java/com/android/internal/compat/OverrideAllowedState.java +++ b/core/java/com/android/internal/compat/OverrideAllowedState.java @@ -34,7 +34,8 @@ public final class OverrideAllowedState implements Parcelable { DISABLED_NON_TARGET_SDK, DISABLED_TARGET_SDK_TOO_HIGH, DEFERRED_VERIFICATION, - LOGGING_ONLY_CHANGE + LOGGING_ONLY_CHANGE, + PLATFORM_TOO_OLD }) @Retention(RetentionPolicy.SOURCE) public @interface State { @@ -65,6 +66,10 @@ public final class OverrideAllowedState implements Parcelable { * Change is marked as logging only, and cannot be toggled. */ public static final int LOGGING_ONLY_CHANGE = 5; + /** + * Change is gated by a target sdk version newer than the current platform sdk version. + */ + public static final int PLATFORM_TOO_OLD = 6; @State public final int state; @@ -123,6 +128,11 @@ public final class OverrideAllowedState implements Parcelable { throw new SecurityException(String.format( "Cannot override %1$d because it is marked as a logging-only change.", changeId)); + case PLATFORM_TOO_OLD: + throw new SecurityException(String.format( + "Cannot override %1$d for %2$s because the change's targetSdk threshold " + + "(%3$d) is above the platform sdk.", + changeId, packageName, changeIdTargetSdk)); } } @@ -170,6 +180,8 @@ public final class OverrideAllowedState implements Parcelable { return "DEFERRED_VERIFICATION"; case LOGGING_ONLY_CHANGE: return "LOGGING_ONLY_CHANGE"; + case PLATFORM_TOO_OLD: + return "PLATFORM_TOO_OLD"; } return "UNKNOWN"; } diff --git a/core/java/com/android/internal/graphics/palette/Mean.java b/core/java/com/android/internal/graphics/palette/Mean.java index 894f91b6261c..bde036349d3b 100644 --- a/core/java/com/android/internal/graphics/palette/Mean.java +++ b/core/java/com/android/internal/graphics/palette/Mean.java @@ -22,20 +22,19 @@ import java.util.Random; * Represents a centroid in Kmeans algorithms. */ public class Mean { - private static final Random RANDOM = new Random(0); - public float[] center; /** * Constructor. * * @param upperBound maximum value of a dimension in the space Kmeans is optimizing in + * @param random used to generate a random center */ - Mean(int upperBound) { + Mean(int upperBound, Random random) { center = new float[]{ - RANDOM.nextInt(upperBound + 1), RANDOM.nextInt(upperBound + 1), - RANDOM.nextInt(upperBound + 1) + random.nextInt(upperBound + 1), random.nextInt(upperBound + 1), + random.nextInt(upperBound + 1) }; } diff --git a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java index a87a34f4ae11..b4f216ba87fa 100644 --- a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java +++ b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.Set; @@ -57,13 +58,27 @@ public class WSMeansQuantizer implements Quantizer { } if (maxColors > means.length) { + // Always initialize Random with the same seed. Ensures the results of quantization + // are consistent, even when random centroids are required. + Random random = new Random(0x42688); int randomMeansToCreate = maxColors - means.length; for (int i = 0; i < randomMeansToCreate; i++) { - mMeans[means.length + i] = new Mean(100); + mMeans[means.length + i] = new Mean(100, random); } } for (int pixel : pixels) { + // These are pixels from the bitmap that is being quantized. + // Depending on the bitmap & downscaling, it may have pixels that are less than opaque + // Ignore those pixels. + /// + // Note: they don't _have_ to be ignored, for example, we could instead turn them + // opaque. Traditionally, including outside Android, quantizers ignore transparent + // pixels, so that strategy was chosen. + int alpha = (pixel >> 24); + if (alpha < 255) { + continue; + } Integer currentCount = mCountByColor.get(pixel); if (currentCount == null) { currentCount = 0; @@ -105,8 +120,12 @@ public class WSMeansQuantizer implements Quantizer { /** Create random starting centroids for K-means. */ public static float[][] randomMeans(int maxColors, int upperBound) { float[][] means = new float[maxColors][]; + + // Always initialize Random with the same seed. Ensures the results of quantization + // are consistent, even when random centroids are required. + Random random = new Random(0x42688); for (int i = 0; i < maxColors; i++) { - means[i] = new Mean(upperBound).center; + means[i] = new Mean(upperBound, random).center; } return means; } diff --git a/core/java/com/android/internal/graphics/palette/WuQuantizer.java b/core/java/com/android/internal/graphics/palette/WuQuantizer.java index 66206bf8297a..a2652ea6d5e1 100644 --- a/core/java/com/android/internal/graphics/palette/WuQuantizer.java +++ b/core/java/com/android/internal/graphics/palette/WuQuantizer.java @@ -78,7 +78,12 @@ public class WuQuantizer implements Quantizer { // All of the sample Wu implementations are reimplementations of a snippet of C code from // the early 90s. They all cap the maximum # of colors at 256, and it is impossible to tell // if this is a requirement, a consequence of QUANT_SIZE, or arbitrary. - this.mMaxColors = Math.min(MAX_COLORS, maxColorCount); + // + // Also, the number of maximum colors should be capped at the number of pixels - otherwise, + // If extraction is run on a set of pixels whose count is less than max colors, + // then colors.length < max colors, and accesses to colors[index] throw an + // ArrayOutOfBoundsException. + this.mMaxColors = Math.min(Math.min(MAX_COLORS, maxColorCount), colors.length); Box[] cube = new Box[mMaxColors]; int red, green, blue; @@ -119,17 +124,13 @@ public class WuQuantizer implements Quantizer { } } - // If extraction is run on a set of pixels whose count is less than the - // number of max colors, then colors.length < max colors, and accesses - // to colors[index] inside the for loop throw an ArrayOutOfBoundsException. - int numColorsToCreate = (int) Math.min(mMaxColors, colors.length); - for (k = 0; k < numColorsToCreate; ++k) { + for (k = 0; k < mMaxColors; ++k) { weight = getVolume(cube[k], mWt); if (weight > 0) { red = (int) (getVolume(cube[k], mMr) / weight); green = (int) (getVolume(cube[k], mMg) / weight); blue = (int) (getVolume(cube[k], mMb) / weight); - colors[k] = ((red & 0x0ff) << 16) | ((green & 0x0ff) << 8) | (blue & 0x0ff); + colors[k] = (255 << 24) | (red << 16) | (green << 8) | blue; } else { colors[k] = 0; } diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java index 5829047ad642..7f0178e29d85 100644 --- a/core/java/com/android/internal/jank/FrameTracker.java +++ b/core/java/com/android/internal/jank/FrameTracker.java @@ -206,9 +206,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener * Cancel the trace session of the CUJ. */ public synchronized void cancel() { - // The session is ongoing, end the trace session. - // That means the cancel call is from external invocation, not from end(). - if (mBeginVsyncId != INVALID_ID && mEndVsyncId == INVALID_ID) { + // We don't need to end the trace section if it never begun. + if (mBeginVsyncId != INVALID_ID) { Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId); } mCancelled = true; diff --git a/core/java/com/android/internal/os/SelectedProcessCpuThreadReader.java b/core/java/com/android/internal/os/SelectedProcessCpuThreadReader.java new file mode 100644 index 000000000000..2ffff73f18cf --- /dev/null +++ b/core/java/com/android/internal/os/SelectedProcessCpuThreadReader.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import android.annotation.Nullable; +import android.os.Process; + +/** + * Reads CPU usage statistics about a selected process identified by its cmdline. + * + * Handles finding the pid for the process and delegates CPU usage reading from the eBPF map to + * KernelSingleProcessCpuThreadReader. Exactly one long-lived instance of the process is expected. + * Otherwise, no statistics are returned. + * + * See also SystemServerCpuThreadReader. + */ +public final class SelectedProcessCpuThreadReader { + private final String[] mCmdline; + + private int mPid; + private KernelSingleProcessCpuThreadReader mKernelCpuThreadReader; + + public SelectedProcessCpuThreadReader(String cmdline) { + mCmdline = new String[] { cmdline }; + } + + /** Returns CPU times, per thread group, since tracking started. */ + @Nullable + public KernelSingleProcessCpuThreadReader.ProcessCpuUsage readAbsolute() { + int[] pids = Process.getPidsForCommands(mCmdline); + if (pids == null || pids.length != 1) { + return null; + } + int pid = pids[0]; + if (mPid == pid) { + return mKernelCpuThreadReader.getProcessCpuUsage(); + } + mPid = pid; + mKernelCpuThreadReader = KernelSingleProcessCpuThreadReader.create(mPid); + mKernelCpuThreadReader.startTrackingThreadCpuTimes(); + return null; + } +} diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java index bed85aed3625..83309fc61009 100644 --- a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java @@ -359,18 +359,6 @@ public class BaseProtoLogImpl { + "\nLogging definitions loaded: " + mViewerConfig.knownViewerStringsNumber(); } - /** - * Writes the log buffer to a new file for the bugreport. - * - * This method is synchronized with {@code #startProtoLog(PrintWriter)} and - * {@link #stopProtoLog(PrintWriter, boolean)}. - */ - public void writeProtoLogToFile() { - synchronized (mProtoLogEnabledLock) { - writeProtoLogToFileLocked(); - } - } - private void writeProtoLogToFileLocked() { try { long offset = diff --git a/core/java/com/android/internal/security/OWNERS b/core/java/com/android/internal/security/OWNERS new file mode 100644 index 000000000000..41d1d6687c42 --- /dev/null +++ b/core/java/com/android/internal/security/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 36824 + +per-file VerityUtils.java = victorhsieh@google.com diff --git a/services/core/java/com/android/server/security/TEST_MAPPING b/core/java/com/android/internal/security/TEST_MAPPING index 9a5e90e8681f..9a5e90e8681f 100644 --- a/services/core/java/com/android/server/security/TEST_MAPPING +++ b/core/java/com/android/internal/security/TEST_MAPPING diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/core/java/com/android/internal/security/VerityUtils.java index 48a60387fee7..ef703a996001 100644 --- a/services/core/java/com/android/server/security/VerityUtils.java +++ b/core/java/com/android/internal/security/VerityUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.security; +package com.android.internal.security; import android.annotation.NonNull; import android.os.Build; @@ -42,7 +42,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; /** Provides fsverity related operations. */ -abstract public class VerityUtils { +public abstract class VerityUtils { private static final String TAG = "VerityUtils"; /** @@ -156,8 +156,8 @@ abstract public class VerityUtils { return SetupResult.failed(); } return SetupResult.ok(Os.dup(rfd), contentSize); - } catch (IOException | SecurityException | DigestException | NoSuchAlgorithmException | - SignatureNotFoundException | ErrnoException e) { + } catch (IOException | SecurityException | DigestException | NoSuchAlgorithmException + | SignatureNotFoundException | ErrnoException e) { Slog.e(TAG, "Failed to set up apk verity: ", e); return SetupResult.failed(); } finally { @@ -243,14 +243,20 @@ abstract public class VerityUtils { private final FileDescriptor mFileDescriptor; private final int mContentSize; + /** @deprecated */ + @Deprecated public static SetupResult ok(@NonNull FileDescriptor fileDescriptor, int contentSize) { return new SetupResult(RESULT_OK, fileDescriptor, contentSize); } + /** @deprecated */ + @Deprecated public static SetupResult skipped() { return new SetupResult(RESULT_SKIPPED, null, -1); } + /** @deprecated */ + @Deprecated public static SetupResult failed() { return new SetupResult(RESULT_FAILED, null, -1); } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 200e0dd6e65b..fea07519fb4d 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -257,4 +257,12 @@ oneway interface IStatusBar * file descriptor passed in. */ void passThroughShellCommand(in String[] args, in ParcelFileDescriptor pfd); + + /** + * Enables/disables the navigation bar luma sampling. + * + * @param displayId the id of the display to notify. + * @param enable {@code true} if enable, otherwise set to {@code false}. + */ + void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable); } diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl index ee94ef8ddda3..85114e59cc2d 100644 --- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -42,7 +42,8 @@ oneway interface IPhoneStateListener { // Uses CellIdentity which is Parcelable here; will convert to CellLocation in client. void onCellLocationChanged(in CellIdentity location); - void onCallStateChanged(int state, String incomingNumber); + void onLegacyCallStateChanged(int state, String incomingNumber); + void onCallStateChanged(int state); void onDataConnectionStateChanged(int state, int networkType); void onDataActivity(int direction); void onSignalStrengthsChanged(in SignalStrength signalStrength); diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java index dc6880e4f997..90c728293eb0 100644 --- a/core/java/com/android/internal/util/LatencyTracker.java +++ b/core/java/com/android/internal/util/LatencyTracker.java @@ -175,7 +175,7 @@ public class LatencyTracker { mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED); for (int action : ACTIONS_ALL) { mTraceThresholdPerAction[action] = - properties.getInt(getTraceTriggerNameForAction(action), -1); + properties.getInt(getNameOfAction(STATSD_ACTION[action]), -1); } } } diff --git a/core/java/com/android/internal/util/ScreenRecordHelper.java b/core/java/com/android/internal/util/ScreenRecordHelper.java deleted file mode 100644 index ec7ed4e0008a..000000000000 --- a/core/java/com/android/internal/util/ScreenRecordHelper.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.util; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; - -/** - * Helper class to initiate a screen recording - */ -public class ScreenRecordHelper { - private final Context mContext; - - /** - * Create a new ScreenRecordHelper for the given context - * @param context - */ - public ScreenRecordHelper(Context context) { - mContext = context; - } - - /** - * Show dialog of screen recording options to user. - */ - public void launchRecordPrompt() { - final ComponentName launcherComponent = ComponentName.unflattenFromString( - mContext.getResources().getString( - com.android.internal.R.string.config_screenRecorderComponent)); - final Intent intent = new Intent(); - intent.setComponent(launcherComponent); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); - } -} diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java index 19506a325d9a..d0c807d24b14 100644 --- a/core/java/com/android/internal/view/IInputConnectionWrapper.java +++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java @@ -31,8 +31,10 @@ import android.util.imetracing.ImeTracing; import android.util.imetracing.InputConnectionHelper; import android.util.proto.ProtoOutputStream; import android.view.KeyEvent; +import android.view.View; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CorrectionInfo; +import android.view.inputmethod.DumpableInputConnection; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; @@ -49,7 +51,9 @@ import com.android.internal.inputmethod.IIntResultCallback; import com.android.internal.inputmethod.ISurroundingTextResultCallback; import com.android.internal.os.SomeArgs; -public abstract class IInputConnectionWrapper extends IInputContext.Stub { +import java.lang.ref.WeakReference; + +public final class IInputConnectionWrapper extends IInputContext.Stub { private static final String TAG = "IInputConnectionWrapper"; private static final boolean DEBUG = false; @@ -90,10 +94,13 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub { private Looper mMainLooper; private Handler mH; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private Object mLock = new Object(); + private final Object mLock = new Object(); @GuardedBy("mLock") private boolean mFinished = false; + private final InputMethodManager mParentInputMethodManager; + private final WeakReference<View> mServedView; + class MyHandler extends Handler { MyHandler(Looper looper) { super(looper); @@ -104,11 +111,15 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub { executeMessage(msg); } } - - public IInputConnectionWrapper(Looper mainLooper, @NonNull InputConnection inputConnection) { + + public IInputConnectionWrapper(@NonNull Looper mainLooper, + @NonNull InputConnection inputConnection, + @NonNull InputMethodManager inputMethodManager, @Nullable View servedView) { mInputConnection = inputConnection; mMainLooper = mainLooper; mH = new MyHandler(mMainLooper); + mParentInputMethodManager = inputMethodManager; + mServedView = new WeakReference<>(servedView); } @Nullable @@ -118,21 +129,70 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub { } } - protected Looper getLooper() { - synchronized (mMainLooper) { - return mMainLooper; + private boolean isFinished() { + synchronized (mLock) { + return mFinished; } } - protected boolean isFinished() { - synchronized (mLock) { - return mFinished; + public boolean isActive() { + return mParentInputMethodManager.isActive() && !isFinished(); + } + + public View getServedView() { + return mServedView.get(); + } + + public void deactivate() { + if (isFinished()) { + // This is a small performance optimization. Still only the 1st call of + // reportFinish() will take effect. + return; + } + closeConnection(); + + // Notify the app that the InputConnection was closed. + final View servedView = mServedView.get(); + if (servedView != null) { + final Handler handler = servedView.getHandler(); + // The handler is null if the view is already detached. When that's the case, for + // now, we simply don't dispatch this callback. + if (handler != null) { + if (DEBUG) { + Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView); + } + if (handler.getLooper().isCurrentThread()) { + servedView.onInputConnectionClosedInternal(); + } else { + handler.post(servedView::onInputConnectionClosedInternal); + } + } } } - protected abstract boolean isActive(); + @Override + public String toString() { + return "IInputConnectionWrapper{" + + "connection=" + getInputConnection() + + " finished=" + isFinished() + + " mParentInputMethodManager.isActive()=" + mParentInputMethodManager.isActive() + + " mServedView=" + mServedView.get() + + "}"; + } - protected abstract InputMethodManager getIMM(); + public void dumpDebug(ProtoOutputStream proto, long fieldId) { + synchronized (mLock) { + // Check that the call is initiated in the main thread of the current InputConnection + // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are + // executed on this thread. Otherwise the messages are dispatched to the correct thread + // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance + // reasons. + if ((mInputConnection instanceof DumpableInputConnection) + && Looper.myLooper() == mMainLooper) { + ((DumpableInputConnection) mInputConnection).dumpDebug(proto, fieldId); + } + } + } public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) { dispatchMessage(mH.obtainMessage(DO_GET_TEXT_AFTER_CURSOR, length, flags, callback)); @@ -161,6 +221,10 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub { dispatchMessage(mH.obtainMessage(DO_GET_SURROUNDING_TEXT, flags, 0 /* unused */, args)); } + public void setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) { + // no-op + } + public void getCursorCapsMode(int reqModes, IIntResultCallback callback) { dispatchMessage( mH.obtainMessage(DO_GET_CURSOR_CAPS_MODE, reqModes, 0 /* unused */, callback)); @@ -309,7 +373,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub { icProto = InputConnectionHelper.buildGetTextAfterCursorProto(msg.arg1, msg.arg2, result); ImeTracing.getInstance().triggerClientDump( - TAG + "#getTextAfterCursor", getIMM(), icProto); + TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto); } try { callback.onResult(result); @@ -339,7 +403,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub { icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(msg.arg1, msg.arg2, result); ImeTracing.getInstance().triggerClientDump( - TAG + "#getTextBeforeCursor", getIMM(), icProto); + TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto); } try { callback.onResult(result); @@ -368,7 +432,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub { if (ImeTracing.getInstance().isEnabled()) { icProto = InputConnectionHelper.buildGetSelectedTextProto(msg.arg1, result); ImeTracing.getInstance().triggerClientDump( - TAG + "#getSelectedText", getIMM(), icProto); + TAG + "#getSelectedText", mParentInputMethodManager, icProto); } try { callback.onResult(result); @@ -402,7 +466,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub { icProto = InputConnectionHelper.buildGetSurroundingTextProto(beforeLength, afterLength, flags, result); ImeTracing.getInstance().triggerClientDump( - TAG + "#getSurroundingText", getIMM(), icProto); + TAG + "#getSurroundingText", mParentInputMethodManager, icProto); } try { callback.onResult(result); @@ -432,7 +496,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub { icProto = InputConnectionHelper.buildGetCursorCapsModeProto(msg.arg1, result); ImeTracing.getInstance().triggerClientDump( - TAG + "#getCursorCapsMode", getIMM(), icProto); + TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto); } try { callback.onResult(result); @@ -464,7 +528,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub { icProto = InputConnectionHelper.buildGetExtractedTextProto(request, msg.arg1, result); ImeTracing.getInstance().triggerClientDump( - TAG + "#getExtractedText", getIMM(), icProto); + TAG + "#getExtractedText", mParentInputMethodManager, icProto); } try { callback.onResult(result); diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl index c33637353984..8d82e33dc29f 100644 --- a/core/java/com/android/internal/view/IInputMethod.aidl +++ b/core/java/com/android/internal/view/IInputMethod.aidl @@ -35,7 +35,8 @@ import com.android.internal.view.InlineSuggestionsRequestInfo; * {@hide} */ oneway interface IInputMethod { - void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps); + void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps, + int configChanges); void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo, in IInlineSuggestionsRequestCallback cb); diff --git a/core/java/com/android/internal/view/OWNERS b/core/java/com/android/internal/view/OWNERS index 851d1f37522a..eb2478f6550a 100644 --- a/core/java/com/android/internal/view/OWNERS +++ b/core/java/com/android/internal/view/OWNERS @@ -18,3 +18,7 @@ per-file AppearanceRegion = file:/services/core/java/com/android/server/wm/OWNER per-file BaseIWIndow.java = file:/services/core/java/com/android/server/wm/OWNERS per-file RotationPolicy.java = file:/services/core/java/com/android/server/wm/OWNERS per-file WindowManagerPolicyThread.java = file:/services/core/java/com/android/server/wm/OWNERS + +# Scroll Capture +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS +per-file *CaptureHelper*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java index e143498293f3..2695b9c7651f 100644 --- a/core/java/com/android/internal/widget/ImageFloatingTextView.java +++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java @@ -36,8 +36,10 @@ import android.widget.TextView; @RemoteViews.RemoteView public class ImageFloatingTextView extends TextView { - /** Number of lines from the top to indent */ - private int mIndentLines; + /** Number of lines from the top to indent. */ + private int mIndentLines = 0; + /** Whether or not there is an image to indent for. */ + private boolean mHasImage = false; /** Resolved layout direction */ private int mResolvedDirection = LAYOUT_DIRECTION_UNDEFINED; @@ -96,7 +98,7 @@ public class ImageFloatingTextView extends TextView { // we set the endmargin on the requested number of lines. int[] margins = null; - if (mIndentLines > 0) { + if (mHasImage && mIndentLines > 0) { margins = new int[mIndentLines + 1]; for (int i = 0; i < mIndentLines; i++) { margins[i] = mImageEndMargin; @@ -111,9 +113,24 @@ public class ImageFloatingTextView extends TextView { return builder.build(); } + /** + * @param imageEndMargin the end margin (in pixels) to indent the first few lines of the text + */ @RemotableViewMethod public void setImageEndMargin(int imageEndMargin) { - mImageEndMargin = imageEndMargin; + if (mImageEndMargin != imageEndMargin) { + mImageEndMargin = imageEndMargin; + invalidateTextIfIndenting(); + } + } + + /** + * @param imageEndMarginDp the end margin (in dp) to indent the first few lines of the text + */ + @RemotableViewMethod + public void setImageEndMarginDp(float imageEndMarginDp) { + setImageEndMargin( + (int) (imageEndMarginDp * getResources().getDisplayMetrics().density)); } @Override @@ -121,7 +138,7 @@ public class ImageFloatingTextView extends TextView { int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mPaddingTop - mPaddingBottom; if (getLayout() != null && getLayout().getHeight() != availableHeight) { // We've been measured before and the new size is different than before, lets make sure - // we reset the maximum lines, otherwise we may be cut short + // we reset the maximum lines, otherwise the last line of text may be partially cut off mMaxLinesForHeight = -1; nullLayouts(); } @@ -130,7 +147,7 @@ public class ImageFloatingTextView extends TextView { if (layout.getHeight() > availableHeight) { // With the existing layout, not all of our lines fit on the screen, let's find the // first one that fits and ellipsize at that one. - int maxLines = layout.getLineCount() - 1; + int maxLines = layout.getLineCount(); while (maxLines > 1 && layout.getLineBottom(maxLines - 1) > availableHeight) { maxLines--; } @@ -152,31 +169,43 @@ public class ImageFloatingTextView extends TextView { if (layoutDirection != mResolvedDirection && isLayoutDirectionResolved()) { mResolvedDirection = layoutDirection; - if (mIndentLines > 0) { - // Invalidate layout. - nullLayouts(); - requestLayout(); - } + invalidateTextIfIndenting(); + } + } + + private void invalidateTextIfIndenting() { + if (mHasImage && mIndentLines > 0) { + // Invalidate layout. + nullLayouts(); + requestLayout(); } } + /** + * @param hasImage whether there is an image to wrap text around. + */ @RemotableViewMethod public void setHasImage(boolean hasImage) { - setNumIndentLines(hasImage ? 2 : 0); + setHasImageAndNumIndentLines(hasImage, mIndentLines); } /** * @param lines the number of lines at the top that should be indented by indentEnd - * @return whether a change was made */ - public boolean setNumIndentLines(int lines) { - if (mIndentLines != lines) { - mIndentLines = lines; - // Invalidate layout. + @RemotableViewMethod + public void setNumIndentLines(int lines) { + setHasImageAndNumIndentLines(mHasImage, lines); + } + + private void setHasImageAndNumIndentLines(boolean hasImage, int lines) { + int oldEffectiveLines = mHasImage ? mIndentLines : 0; + int newEffectiveLines = hasImage ? lines : 0; + mIndentLines = lines; + mHasImage = hasImage; + if (oldEffectiveLines != newEffectiveLines) { + // always invalidate layout. nullLayouts(); requestLayout(); - return true; } - return false; } } diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS index d284d5167843..8e68be0f742a 100644 --- a/core/java/com/android/internal/widget/OWNERS +++ b/core/java/com/android/internal/widget/OWNERS @@ -1,4 +1,6 @@ per-file PointerLocationView.java = michaelwr@google.com, svv@google.com +per-file RecyclerView.java = mount@google.com +per-file ViewPager.java = mount@google.com # LockSettings related per-file *LockPattern* = file:/services/core/java/com/android/server/locksettings/OWNERS diff --git a/core/jni/Android.bp b/core/jni/Android.bp index d6d33873adaa..a153fab10214 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -1,4 +1,3 @@ - package { default_applicable_licenses: ["frameworks_base_core_jni_license"], } @@ -69,10 +68,9 @@ cc_library_shared { "liblog", "libminikin", "libz", - "libziparchive", ], - static_libs: ["libnativehelper_lazy"], + static_libs: ["libnativehelper_lazy", "libziparchive_for_incfs", ], export_include_dirs: [ ".", @@ -214,10 +212,12 @@ cc_library_shared { "com_android_internal_os_Zygote.cpp", "com_android_internal_os_ZygoteCommandBuffer.cpp", "com_android_internal_os_ZygoteInit.cpp", + "com_android_internal_security_VerityUtils.cpp", "hwbinder/EphemeralStorage.cpp", "fd_utils.cpp", "android_hardware_input_InputWindowHandle.cpp", "android_hardware_input_InputApplicationHandle.cpp", + "permission_utils.cpp", ], static_libs: [ @@ -236,6 +236,7 @@ cc_library_shared { "audioflinger-aidl-cpp", "av-types-aidl-cpp", "android.hardware.camera.device@3.2", + "media_permission-aidl-cpp", "libandroidicu", "libbpf_android", "libnetdbpf", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index ddd861380fab..3bc0ef4ee3a0 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -97,6 +97,7 @@ extern int register_android_media_AudioVolumeGroupChangeHandler(JNIEnv *env); extern int register_android_media_MicrophoneInfo(JNIEnv *env); extern int register_android_media_ToneGenerator(JNIEnv *env); extern int register_android_media_midi(JNIEnv *env); +extern int register_android_media_permission_Identity(JNIEnv* env); namespace android { @@ -200,6 +201,7 @@ extern int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *en extern int register_com_android_internal_os_Zygote(JNIEnv *env); extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env); +extern int register_com_android_internal_security_VerityUtils(JNIEnv* env); extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); // Namespace for Android Runtime flags applied during boot time. @@ -1534,6 +1536,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_Zygote), REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer), REG_JNI(register_com_android_internal_os_ZygoteInit), + REG_JNI(register_com_android_internal_security_VerityUtils), REG_JNI(register_com_android_internal_util_VirtualRefBasePtr), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_camera2_CameraMetadata), @@ -1562,6 +1565,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_media_RemoteDisplay), REG_JNI(register_android_media_ToneGenerator), REG_JNI(register_android_media_midi), + REG_JNI(register_android_media_permission_Identity), REG_JNI(register_android_opengl_classes), REG_JNI(register_android_server_NetworkManagementSocketTagger), diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index 0e0f98ec1fc4..7d3febbd5d14 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -22,6 +22,7 @@ #include <jni.h> #include <nativehelper/JNIHelp.h> #include "core_jni_helpers.h" +#include "permission_utils.h" #include <utils/Log.h> #include <media/AudioRecord.h> @@ -39,6 +40,9 @@ // ---------------------------------------------------------------------------- +using android::media::permission::convertIdentity; +using android::media::permission::Identity; + using namespace android; // ---------------------------------------------------------------------------- @@ -181,12 +185,11 @@ static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioR } // ---------------------------------------------------------------------------- -static jint -android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask, - jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName, - jlong nativeRecordInJavaObj) -{ +static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, + jobject jaa, jintArray jSampleRate, jint channelMask, + jint channelIndexMask, jint audioFormat, + jint buffSizeInBytes, jintArray jSession, + jobject jIdentity, jlong nativeRecordInJavaObj) { //ALOGV(">> Entering android_media_AudioRecord_setup"); //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d " // "nativeRecordInJavaObj=0x%llX", @@ -262,10 +265,8 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, size_t frameSize = channelCount * bytesPerSample; size_t frameCount = buffSizeInBytes / frameSize; - ScopedUtfChars opPackageNameStr(env, opPackageName); - // create an uninitialized AudioRecord object - lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str())); + lpRecorder = new AudioRecord(convertIdentity(env, jIdentity)); // read the AudioAttributes values auto paa = JNIAudioAttributeHelper::makeUnique(); @@ -373,8 +374,6 @@ native_init_failure: return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED; } - - // ---------------------------------------------------------------------------- static jint android_media_AudioRecord_start(JNIEnv *env, jobject thiz, jint event, jint triggerSession) @@ -893,9 +892,11 @@ static jint android_media_AudioRecord_get_port_id(JNIEnv *env, jobject thiz) { // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { + // name, signature, funcPtr {"native_start", "(II)I", (void *)android_media_AudioRecord_start}, {"native_stop", "()V", (void *)android_media_AudioRecord_stop}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I", + {"native_setup", + "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/media/permission/Identity;J)I", (void *)android_media_AudioRecord_setup}, {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize}, {"native_release", "()V", (void *)android_media_AudioRecord_release}, diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 94bd28a59e7c..f102edc79e7f 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -2204,13 +2204,11 @@ android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP( return jStatus; } -static jint -android_media_AudioSystem_getSurroundFormats(JNIEnv *env, jobject thiz, - jobject jSurroundFormats, jboolean reported) -{ +static jint android_media_AudioSystem_getSurroundFormats(JNIEnv *env, jobject thiz, + jobject jSurroundFormats) { ALOGV("getSurroundFormats"); - if (jSurroundFormats == NULL) { + if (jSurroundFormats == nullptr) { ALOGE("jSurroundFormats is NULL"); return (jint)AUDIO_JAVA_BAD_VALUE; } @@ -2221,10 +2219,10 @@ android_media_AudioSystem_getSurroundFormats(JNIEnv *env, jobject thiz, jint jStatus; unsigned int numSurroundFormats = 0; - audio_format_t *surroundFormats = NULL; - bool *surroundFormatsEnabled = NULL; - status_t status = AudioSystem::getSurroundFormats( - &numSurroundFormats, surroundFormats, surroundFormatsEnabled, reported); + audio_format_t *surroundFormats = nullptr; + bool *surroundFormatsEnabled = nullptr; + status_t status = AudioSystem::getSurroundFormats(&numSurroundFormats, surroundFormats, + surroundFormatsEnabled); if (status != NO_ERROR) { ALOGE_IF(status != NO_ERROR, "AudioSystem::getSurroundFormats error %d", status); jStatus = nativeToJavaStatus(status); @@ -2236,8 +2234,8 @@ android_media_AudioSystem_getSurroundFormats(JNIEnv *env, jobject thiz, } surroundFormats = (audio_format_t *)calloc(numSurroundFormats, sizeof(audio_format_t)); surroundFormatsEnabled = (bool *)calloc(numSurroundFormats, sizeof(bool)); - status = AudioSystem::getSurroundFormats( - &numSurroundFormats, surroundFormats, surroundFormatsEnabled, reported); + status = AudioSystem::getSurroundFormats(&numSurroundFormats, surroundFormats, + surroundFormatsEnabled); jStatus = nativeToJavaStatus(status); if (status != NO_ERROR) { ALOGE_IF(status != NO_ERROR, "AudioSystem::getSurroundFormats error %d", status); @@ -2258,6 +2256,50 @@ exit: return jStatus; } +static jint android_media_AudioSystem_getReportedSurroundFormats(JNIEnv *env, jobject thiz, + jobject jSurroundFormats) { + ALOGV("getReportedSurroundFormats"); + + if (jSurroundFormats == nullptr) { + ALOGE("jSurroundFormats is NULL"); + return (jint)AUDIO_JAVA_BAD_VALUE; + } + if (!env->IsInstanceOf(jSurroundFormats, gArrayListClass)) { + ALOGE("jSurroundFormats not an arraylist"); + return (jint)AUDIO_JAVA_BAD_VALUE; + } + jint jStatus; + unsigned int numSurroundFormats = 0; + audio_format_t *surroundFormats = nullptr; + status_t status = AudioSystem::getReportedSurroundFormats(&numSurroundFormats, surroundFormats); + if (status != NO_ERROR) { + ALOGE_IF(status != NO_ERROR, "AudioSystem::getReportedSurroundFormats error %d", status); + jStatus = nativeToJavaStatus(status); + goto exit; + } + if (numSurroundFormats == 0) { + jStatus = (jint)AUDIO_JAVA_SUCCESS; + goto exit; + } + surroundFormats = (audio_format_t *)calloc(numSurroundFormats, sizeof(audio_format_t)); + status = AudioSystem::getReportedSurroundFormats(&numSurroundFormats, surroundFormats); + jStatus = nativeToJavaStatus(status); + if (status != NO_ERROR) { + ALOGE_IF(status != NO_ERROR, "AudioSystem::getReportedSurroundFormats error %d", status); + goto exit; + } + for (size_t i = 0; i < numSurroundFormats; i++) { + jobject surroundFormat = env->NewObject(gIntegerClass, gIntegerCstor, + audioFormatFromNative(surroundFormats[i])); + env->CallObjectMethod(jSurroundFormats, gArrayListMethods.add, surroundFormat); + env->DeleteLocalRef(surroundFormat); + } + +exit: + free(surroundFormats); + return jStatus; +} + static jint android_media_AudioSystem_setSurroundFormatEnabled(JNIEnv *env, jobject thiz, jint audioFormat, jboolean enabled) @@ -2619,8 +2661,10 @@ static const JNINativeMethod gMethods[] = (void *)android_media_AudioSystem_getOffloadSupport}, {"getMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_AudioSystem_getMicrophones}, - {"getSurroundFormats", "(Ljava/util/Map;Z)I", + {"getSurroundFormats", "(Ljava/util/Map;)I", (void *)android_media_AudioSystem_getSurroundFormats}, + {"getReportedSurroundFormats", "(Ljava/util/ArrayList;)I", + (void *)android_media_AudioSystem_getReportedSurroundFormats}, {"setSurroundFormatEnabled", "(IZ)I", (void *)android_media_AudioSystem_setSurroundFormatEnabled}, {"setAssistantUid", "(I)I", (void *)android_media_AudioSystem_setAssistantUid}, diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index cae6db57e99c..62767a676e8b 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -48,6 +48,7 @@ using namespace android; using ::android::media::VolumeShaper; +using ::android::media::permission::Identity; // ---------------------------------------------------------------------------- static const char* const kClassPathName = "android/media/AudioTrack"; @@ -328,7 +329,10 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we // create the native AudioTrack object ScopedUtfChars opPackageNameStr(env, opPackageName); - lpTrack = new AudioTrack(opPackageNameStr.c_str()); + // TODO b/182469354: make consistent with AudioRecord + Identity identity = Identity(); + identity.packageName = std::string(opPackageNameStr.c_str()); + lpTrack = new AudioTrack(identity); // read the AudioAttributes values auto paa = JNIAudioAttributeHelper::makeUnique(); @@ -390,8 +394,8 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we sessionId, // audio session ID offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC, - (offload || encapsulationMode) ? &offloadInfo : NULL, -1, - -1, // default uid, pid values + (offload || encapsulationMode) ? &offloadInfo : NULL, + Identity(), // default uid, pid values paa.get()); break; @@ -416,8 +420,8 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we true, // thread can call Java sessionId, // audio session ID AudioTrack::TRANSFER_SHARED, - NULL, // default offloadInfo - -1, -1, // default uid, pid values + NULL, // default offloadInfo + Identity(), // default uid, pid values paa.get()); break; diff --git a/core/jni/android_os_incremental_IncrementalManager.cpp b/core/jni/android_os_incremental_IncrementalManager.cpp index 2384efaf1a54..413bcef57a64 100644 --- a/core/jni/android_os_incremental_IncrementalManager.cpp +++ b/core/jni/android_os_incremental_IncrementalManager.cpp @@ -41,6 +41,10 @@ static jboolean nativeIsIncrementalPath(JNIEnv* env, return (jboolean)IncFs_IsIncFsPath(path.c_str()); } +static jboolean nativeIsIncrementalFd(JNIEnv* env, jobject clazz, jint fd) { + return (jboolean)IncFs_IsIncFsFd(fd); +} + static jbyteArray nativeUnsafeGetFileSignature(JNIEnv* env, jobject clazz, jstring javaPath) { ScopedUtfChars path(env, javaPath); @@ -61,6 +65,7 @@ static const JNINativeMethod method_table[] = {{"nativeIsEnabled", "()Z", (void*)nativeIsEnabled}, {"nativeIsV2Available", "()Z", (void*)nativeIsV2Available}, {"nativeIsIncrementalPath", "(Ljava/lang/String;)Z", (void*)nativeIsIncrementalPath}, + {"nativeIsIncrementalFd", "(I)Z", (void*)nativeIsIncrementalFd}, {"nativeUnsafeGetFileSignature", "(Ljava/lang/String;)[B", (void*)nativeUnsafeGetFileSignature}}; diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index 5e142fd10de0..ab6633f395a8 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -57,6 +57,7 @@ static struct { jmethodID dispatchInputEvent; jmethodID onFocusEvent; jmethodID onPointerCaptureEvent; + jmethodID onDragEvent; jmethodID onBatchedInputEventPending; } gInputEventReceiverClassInfo; @@ -400,6 +401,18 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, finishInputEvent(seq, true /* handled */); continue; } + case AINPUT_EVENT_TYPE_DRAG: { + const DragEvent* dragEvent = static_cast<DragEvent*>(inputEvent); + if (kDebugDispatchCycle) { + ALOGD("channel '%s' ~ Received drag event: isExiting=%s", + getInputChannelName().c_str(), toString(dragEvent->isExiting())); + } + env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.onDragEvent, + jboolean(dragEvent->isExiting()), dragEvent->getX(), + dragEvent->getY()); + finishInputEvent(seq, true /* handled */); + continue; + } default: assert(false); // InputConsumer should prevent this from ever happening @@ -547,6 +560,8 @@ int register_android_view_InputEventReceiver(JNIEnv* env) { gInputEventReceiverClassInfo.onPointerCaptureEvent = GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onPointerCaptureEvent", "(Z)V"); + gInputEventReceiverClassInfo.onDragEvent = + GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onDragEvent", "(ZFF)V"); gInputEventReceiverClassInfo.onBatchedInputEventPending = GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onBatchedInputEventPending", "(I)V"); diff --git a/core/jni/com_android_internal_os_KernelCpuBpfTracking.cpp b/core/jni/com_android_internal_os_KernelCpuBpfTracking.cpp index 6b41b2ec8f93..d644e3709045 100644 --- a/core/jni/com_android_internal_os_KernelCpuBpfTracking.cpp +++ b/core/jni/com_android_internal_os_KernelCpuBpfTracking.cpp @@ -30,13 +30,13 @@ static jboolean KernelCpuBpfTracking_startTrackingInternal(JNIEnv *, jobject) { static jlongArray KernelCpuBpfTracking_getFreqsInternal(JNIEnv *env, jobject) { auto freqs = android::bpf::getCpuFreqs(); - if (!freqs) return NULL; + if (!freqs) return nullptr; std::vector<uint64_t> allFreqs; for (const auto &vec : *freqs) std::copy(vec.begin(), vec.end(), std::back_inserter(allFreqs)); auto ar = env->NewLongArray(allFreqs.size()); - if (ar != NULL) { + if (ar != nullptr) { env->SetLongArrayRegion(ar, 0, allFreqs.size(), reinterpret_cast<const jlong *>(allFreqs.data())); } @@ -45,7 +45,7 @@ static jlongArray KernelCpuBpfTracking_getFreqsInternal(JNIEnv *env, jobject) { static jintArray KernelCpuBpfTracking_getFreqsClustersInternal(JNIEnv *env, jobject) { auto freqs = android::bpf::getCpuFreqs(); - if (!freqs) return NULL; + if (!freqs) return nullptr; std::vector<uint32_t> freqsClusters; uint32_t clusters = freqs->size(); @@ -54,7 +54,7 @@ static jintArray KernelCpuBpfTracking_getFreqsClustersInternal(JNIEnv *env, jobj } auto ar = env->NewIntArray(freqsClusters.size()); - if (ar != NULL) { + if (ar != nullptr) { env->SetIntArrayRegion(ar, 0, freqsClusters.size(), reinterpret_cast<const jint *>(freqsClusters.data())); } diff --git a/core/jni/com_android_internal_os_KernelCpuTotalBpfMapReader.cpp b/core/jni/com_android_internal_os_KernelCpuTotalBpfMapReader.cpp index ad43014d321f..472bd23c0f8d 100644 --- a/core/jni/com_android_internal_os_KernelCpuTotalBpfMapReader.cpp +++ b/core/jni/com_android_internal_os_KernelCpuTotalBpfMapReader.cpp @@ -22,7 +22,7 @@ namespace android { static jlongArray KernelCpuTotalBpfMapReader_readInternal(JNIEnv *env, jobject) { auto freqTimes = android::bpf::getTotalCpuFreqTimes(); - if (!freqTimes) return JNI_FALSE; + if (!freqTimes) return nullptr; std::vector<uint64_t> allTimes; for (const auto &vec : *freqTimes) { @@ -32,7 +32,7 @@ static jlongArray KernelCpuTotalBpfMapReader_readInternal(JNIEnv *env, jobject) } auto ar = env->NewLongArray(allTimes.size()); - if (ar != NULL) { + if (ar != nullptr) { env->SetLongArrayRegion(ar, 0, allTimes.size(), reinterpret_cast<const jlong *>(allTimes.data())); } diff --git a/core/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp b/core/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp index 7900d301dbb0..098a4d868269 100644 --- a/core/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp +++ b/core/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp @@ -37,7 +37,7 @@ static jlongArray getUidArray(JNIEnv *env, jobject sparseAr, uint32_t uid, jsize jlongArray ar = (jlongArray)env->CallObjectMethod(sparseAr, gSparseArrayClassInfo.get, uid); if (!ar) { ar = env->NewLongArray(sz); - if (ar == NULL) return ar; + if (ar == nullptr) return ar; env->CallVoidMethod(sparseAr, gSparseArrayClassInfo.put, uid, ar); } return ar; @@ -65,7 +65,7 @@ static jboolean KernelCpuUidFreqTimeBpfMapReader_readBpfData(JNIEnv *env, jobjec static uint64_t lastUpdate = 0; uint64_t newLastUpdate = lastUpdate; auto sparseAr = env->GetObjectField(thiz, gmData); - if (sparseAr == NULL) return false; + if (sparseAr == nullptr) return false; auto data = android::bpf::getUidsUpdatedCpuFreqTimes(&newLastUpdate); if (!data.has_value()) return false; @@ -75,7 +75,7 @@ static jboolean KernelCpuUidFreqTimeBpfMapReader_readBpfData(JNIEnv *env, jobjec for (const auto &subVec : times) s += subVec.size(); } jlongArray ar = getUidArray(env, sparseAr, uid, s); - if (ar == NULL) return false; + if (ar == nullptr) return false; copy2DVecToArray(env, ar, times); } lastUpdate = newLastUpdate; @@ -91,7 +91,7 @@ static jboolean KernelCpuUidActiveTimeBpfMapReader_readBpfData(JNIEnv *env, jobj static uint64_t lastUpdate = 0; uint64_t newLastUpdate = lastUpdate; auto sparseAr = env->GetObjectField(thiz, gmData); - if (sparseAr == NULL) return false; + if (sparseAr == nullptr) return false; auto data = android::bpf::getUidsUpdatedConcurrentTimes(&newLastUpdate); if (!data.has_value()) return false; @@ -99,7 +99,7 @@ static jboolean KernelCpuUidActiveTimeBpfMapReader_readBpfData(JNIEnv *env, jobj // TODO: revise calling code so we can divide by NSEC_PER_MSEC here instead for (auto &time : times.active) time /= NSEC_PER_MSEC; jlongArray ar = getUidArray(env, sparseAr, uid, times.active.size()); - if (ar == NULL) return false; + if (ar == nullptr) return false; env->SetLongArrayRegion(ar, 0, times.active.size(), reinterpret_cast<const jlong *>(times.active.data())); } @@ -111,7 +111,7 @@ static jlongArray KernelCpuUidActiveTimeBpfMapReader_getDataDimensions(JNIEnv *e jlong nCpus = get_nprocs_conf(); auto ar = env->NewLongArray(1); - if (ar != NULL) env->SetLongArrayRegion(ar, 0, 1, &nCpus); + if (ar != nullptr) env->SetLongArrayRegion(ar, 0, 1, &nCpus); return ar; } @@ -124,7 +124,7 @@ static jboolean KernelCpuUidClusterTimeBpfMapReader_readBpfData(JNIEnv *env, job static uint64_t lastUpdate = 0; uint64_t newLastUpdate = lastUpdate; auto sparseAr = env->GetObjectField(thiz, gmData); - if (sparseAr == NULL) return false; + if (sparseAr == nullptr) return false; auto data = android::bpf::getUidsUpdatedConcurrentTimes(&newLastUpdate); if (!data.has_value()) return false; @@ -134,7 +134,7 @@ static jboolean KernelCpuUidClusterTimeBpfMapReader_readBpfData(JNIEnv *env, job for (const auto &subVec : times.policy) s += subVec.size(); } jlongArray ar = getUidArray(env, sparseAr, uid, s); - if (ar == NULL) return false; + if (ar == nullptr) return false; copy2DVecToArray(env, ar, times.policy); } lastUpdate = newLastUpdate; @@ -143,12 +143,12 @@ static jboolean KernelCpuUidClusterTimeBpfMapReader_readBpfData(JNIEnv *env, job static jlongArray KernelCpuUidClusterTimeBpfMapReader_getDataDimensions(JNIEnv *env, jobject) { auto times = android::bpf::getUidConcurrentTimes(0); - if (!times.has_value()) return NULL; + if (!times.has_value()) return nullptr; std::vector<jlong> clusterCores; for (const auto &vec : times->policy) clusterCores.push_back(vec.size()); auto ar = env->NewLongArray(clusterCores.size()); - if (ar != NULL) env->SetLongArrayRegion(ar, 0, clusterCores.size(), clusterCores.data()); + if (ar != nullptr) env->SetLongArrayRegion(ar, 0, clusterCores.size(), clusterCores.data()); return ar; } diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 836074f1d5f7..0bed29b7ba28 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -184,6 +184,17 @@ static constexpr int PROCESS_PRIORITY_MIN = 19; /** The numeric value for the normal priority a process should have. */ static constexpr int PROCESS_PRIORITY_DEFAULT = 0; +/** Exponential back off parameters for storage dir check. */ +static constexpr unsigned int STORAGE_DIR_CHECK_RETRY_MULTIPLIER = 2; +static constexpr unsigned int STORAGE_DIR_CHECK_INIT_INTERVAL_US = 50; +static constexpr unsigned int STORAGE_DIR_CHECK_MAX_INTERVAL_US = 1000; +/** + * Lower bound time we allow storage dir check to sleep. + * If it exceeds 2s, PROC_START_TIMEOUT_MSG will kill the starting app anyway, + * so it's fine to assume max retries is 5 mins. + */ +static constexpr int STORAGE_DIR_CHECK_TIMEOUT_US = 1000 * 1000 * 60 * 5; + /** * A helper class containing accounting information for USAPs. */ @@ -1458,6 +1469,31 @@ static void isolateJitProfile(JNIEnv* env, jobjectArray pkg_data_info_list, } } +static void WaitUntilDirReady(const std::string& target, fail_fn_t fail_fn) { + unsigned int sleepIntervalUs = STORAGE_DIR_CHECK_INIT_INTERVAL_US; + + // This is just an approximate value as it doesn't need to be very accurate. + unsigned int sleepTotalUs = 0; + + const char* dir_path = target.c_str(); + while (sleepTotalUs < STORAGE_DIR_CHECK_TIMEOUT_US) { + if (access(dir_path, F_OK) == 0) { + return; + } + // Failed, so we add exponential backoff and retry + usleep(sleepIntervalUs); + sleepTotalUs += sleepIntervalUs; + sleepIntervalUs = std::min<unsigned int>( + sleepIntervalUs * STORAGE_DIR_CHECK_RETRY_MULTIPLIER, + STORAGE_DIR_CHECK_MAX_INTERVAL_US); + } + // Last chance and get the latest errno if it fails. + if (access(dir_path, F_OK) == 0) { + return; + } + fail_fn(CREATE_ERROR("Error dir is not ready %s: %s", dir_path, strerror(errno))); +} + static void BindMountStorageToLowerFs(const userid_t user_id, const uid_t uid, const char* dir_name, const char* package, fail_fn_t fail_fn) { bool hasSdcardFs = IsSdcardfsUsed(); @@ -1468,6 +1504,10 @@ static void BindMountStorageToLowerFs(const userid_t user_id, const uid_t uid, source = StringPrintf("/mnt/pass_through/%d/emulated/%d/%s/%s", user_id, user_id, dir_name, package); } + + // Directory might be not ready, as prepareStorageDirs() is running asynchronously in ProcessList, + // so wait until dir is created. + WaitUntilDirReady(source, fail_fn); std::string target = StringPrintf("/storage/emulated/%d/%s/%s", user_id, dir_name, package); // As the parent is mounted as tmpfs, we need to create the target dir here. diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/core/jni/com_android_internal_security_VerityUtils.cpp index dda44fb72cfc..411a392a075c 100644 --- a/services/core/jni/com_android_server_security_VerityUtils.cpp +++ b/core/jni/com_android_internal_security_VerityUtils.cpp @@ -19,8 +19,8 @@ #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedPrimitiveArray.h> #include <nativehelper/ScopedUtfChars.h> -#include "jni.h" #include <utils/Log.h> +#include "jni.h" #include <errno.h> #include <fcntl.h> @@ -39,7 +39,7 @@ namespace android { namespace { -int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath, jbyteArray signature) { +int enableFsverity(JNIEnv *env, jobject /* clazz */, jstring filePath, jbyteArray signature) { ScopedUtfChars path(env, filePath); if (path.c_str() == nullptr) { return EINVAL; @@ -124,11 +124,11 @@ const JNINativeMethod sMethods[] = { {"measureFsverityNative", "(Ljava/lang/String;[B)I", (void *)measureFsverity}, }; -} // namespace +} // namespace -int register_android_server_security_VerityUtils(JNIEnv* env) { - return jniRegisterNativeMethods(env, - "com/android/server/security/VerityUtils", sMethods, NELEM(sMethods)); +int register_com_android_internal_security_VerityUtils(JNIEnv *env) { + return jniRegisterNativeMethods(env, "com/android/internal/security/VerityUtils", sMethods, + NELEM(sMethods)); } -} // namespace android +} // namespace android diff --git a/core/jni/permission_utils.cpp b/core/jni/permission_utils.cpp new file mode 100644 index 000000000000..2b7ef9999491 --- /dev/null +++ b/core/jni/permission_utils.cpp @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#include "permission_utils.h" +#include "core_jni_helpers.h" + +static struct { + jfieldID fieldUid; // Identity.uid + jfieldID fieldPid; // Identity.pid + jfieldID fieldPackageName; // Identity.packageName + jfieldID fieldAttributionTag; // Identity.attributionTag +} javaIdentityFields; + +static const JNINativeMethod method_table[] = { + // no static methods, currently +}; + +int register_android_media_permission_Identity(JNIEnv* env) { + jclass identityClass = android::FindClassOrDie(env, "android/media/permission/Identity"); + javaIdentityFields.fieldUid = android::GetFieldIDOrDie(env, identityClass, "uid", "I"); + javaIdentityFields.fieldPid = android::GetFieldIDOrDie(env, identityClass, "pid", "I"); + javaIdentityFields.fieldPackageName = + android::GetFieldIDOrDie(env, identityClass, "packageName", "Ljava/lang/String;"); + javaIdentityFields.fieldAttributionTag = + android::GetFieldIDOrDie(env, identityClass, "attributionTag", "Ljava/lang/String;"); + + return android::RegisterMethodsOrDie(env, "android/media/permission/Identity", method_table, + NELEM(method_table)); +} + +namespace android::media::permission { + +Identity convertIdentity(JNIEnv* env, const jobject& jIdentity) { + Identity identity; + + identity.uid = env->GetIntField(jIdentity, javaIdentityFields.fieldUid); + identity.pid = env->GetIntField(jIdentity, javaIdentityFields.fieldPid); + + jstring packageNameStr = static_cast<jstring>( + env->GetObjectField(jIdentity, javaIdentityFields.fieldPackageName)); + if (packageNameStr == nullptr) { + identity.packageName = std::nullopt; + } else { + identity.packageName = std::string(ScopedUtfChars(env, packageNameStr).c_str()); + } + + jstring attributionTagStr = static_cast<jstring>( + env->GetObjectField(jIdentity, javaIdentityFields.fieldAttributionTag)); + if (attributionTagStr == nullptr) { + identity.attributionTag = std::nullopt; + } else { + identity.attributionTag = std::string(ScopedUtfChars(env, attributionTagStr).c_str()); + } + + return identity; +} + +} // namespace android::media::permission diff --git a/core/jni/permission_utils.h b/core/jni/permission_utils.h new file mode 100644 index 000000000000..d625bb6ba30a --- /dev/null +++ b/core/jni/permission_utils.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android/media/permission/Identity.h> +#include <jni.h> + +namespace android::media::permission { + +Identity convertIdentity(JNIEnv* env, const jobject& jIdentity); +} + +int register_android_media_permission_Identity(JNIEnv* env); diff --git a/core/proto/android/app/OWNERS b/core/proto/android/app/OWNERS index 296abd18aadc..cc479e61b855 100644 --- a/core/proto/android/app/OWNERS +++ b/core/proto/android/app/OWNERS @@ -1 +1 @@ -per-file location_time_zone_manager.proto = nfuller@google.com, mingaleev@google.com +per-file location_time_zone_manager.proto, time_zone_detector.proto = nfuller@google.com, mingaleev@google.com diff --git a/core/proto/android/app/location_time_zone_manager.proto b/core/proto/android/app/location_time_zone_manager.proto index f44d5495f132..891e9fca36aa 100644 --- a/core/proto/android/app/location_time_zone_manager.proto +++ b/core/proto/android/app/location_time_zone_manager.proto @@ -17,6 +17,7 @@ syntax = "proto2"; package android.app.time; +import "frameworks/base/core/proto/android/app/time_zone_detector.proto"; import "frameworks/base/core/proto/android/privacy.proto"; option java_multiple_files = true; @@ -31,15 +32,6 @@ message LocationTimeZoneManagerServiceStateProto { repeated TimeZoneProviderStateProto secondary_provider_states = 3; } -// Represents a GeolocationTimeZoneSuggestion that can be / has been passed to the time zone -// detector. -message GeolocationTimeZoneSuggestionProto { - option (android.msg_privacy).dest = DEST_AUTOMATIC; - - repeated string zone_ids = 1; - repeated string debug_info = 2; -} - // The state tracked for a LocationTimeZoneProvider. message TimeZoneProviderStateProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; diff --git a/core/proto/android/app/time_zone_detector.proto b/core/proto/android/app/time_zone_detector.proto new file mode 100644 index 000000000000..b33ca1d4f476 --- /dev/null +++ b/core/proto/android/app/time_zone_detector.proto @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +package android.app.time; + +import "frameworks/base/core/proto/android/privacy.proto"; + +option java_multiple_files = true; +option java_outer_classname = "TimeZoneDetectorProto"; + +// Represents a GeolocationTimeZoneSuggestion that can be / has been passed to the time zone +// detector. +message GeolocationTimeZoneSuggestionProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + repeated string zone_ids = 1; + repeated string debug_info = 2; +} + +/* + * An obfuscated and simplified time zone suggestion for metrics use. + * + * The suggestion's time zone IDs (which relate to location) are obfuscated by + * mapping them to an ordinal. When the ordinal is assigned consistently across + * several objects (i.e. so the same time zone ID is always mapped to the same + * ordinal), this allows comparisons between those objects. For example, we can + * answer "did these two suggestions agree?", "does the suggestion match the + * device's current time zone?", without leaking knowledge of location. Ordinals + * are also significantly more compact than full IANA TZDB IDs, albeit highly + * unstable and of limited use. + */ +message MetricsTimeZoneSuggestion { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + enum Type { + CERTAIN = 1; + UNCERTAIN = 2; + } + optional Type type = 1; + + // The ordinals for time zone(s) in the suggestion. Always empty for + // UNCERTAIN, and can be empty for CERTAIN, for example when the device is in + // a disputed area / on an ocean. + repeated uint32 time_zone_ordinals = 2; +} diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index f26bf7cdb6c1..a7127ad79401 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -346,6 +346,7 @@ message ActivityRecordProto { optional int32 proc_id = 29; optional bool translucent = 30; optional bool pip_auto_enter_enabled = 31; + optional bool in_size_compat_mode = 32; } /* represents WindowToken */ @@ -406,7 +407,7 @@ message WindowStateProto { optional int64 finished_seamless_rotation_frame = 40; optional WindowFramesProto window_frames = 41; optional bool force_seamless_rotation = 42; - optional bool in_size_compat_mode = 43; + optional bool has_compat_scale = 43; optional float global_scale = 44; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f7eb3648dfc0..99ad6d100e55 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -506,6 +506,8 @@ <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_FAILED" /> <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_SUCCEEDED" /> <protected-broadcast android:name="com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION" /> + <protected-broadcast android:name="com.android.server.ACTION_PROFILE_OFF_DEADLINE" /> + <protected-broadcast android:name="com.android.server.ACTION_TURN_PROFILE_ON_NOTIFICATION" /> <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" /> <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" /> @@ -5257,15 +5259,20 @@ <permission android:name="android.permission.MANAGE_MUSIC_RECOGNITION" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Allows an application to manage speech recognition service. + @hide <p>Not for use by third-party applications.</p> --> + <permission android:name="android.permission.MANAGE_SPEECH_RECOGNITION" + android:protectionLevel="signature" /> + <!-- @SystemApi Allows an application to manage the content suggestions service. @hide <p>Not for use by third-party applications.</p> --> <permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS" - android:protectionLevel="signature" /> + android:protectionLevel="signature" /> <!-- @SystemApi Allows an application to manage the app predictions service. @hide <p>Not for use by third-party applications.</p> --> <permission android:name="android.permission.MANAGE_APP_PREDICTIONS" - android:protectionLevel="signature|appPredictor" /> + android:protectionLevel="signature|appPredictor" /> <!-- @SystemApi Allows an application to manage the search ui service. @hide <p>Not for use by third-party applications.</p> --> diff --git a/core/res/res/layout/notification_template_text_multiline.xml b/core/res/res/layout/notification_template_text_multiline.xml index d632ac9527d1..ec493bcc5082 100644 --- a/core/res/res/layout/notification_template_text_multiline.xml +++ b/core/res/res/layout/notification_template_text_multiline.xml @@ -22,7 +22,7 @@ android:layout_gravity="top" android:layout_marginTop="@dimen/notification_text_margin_top" android:minHeight="@dimen/notification_text_height" - android:ellipsize="marquee" + android:ellipsize="end" android:fadingEdge="horizontal" android:gravity="top" android:maxLines="2" diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 648d2a1034d0..7d7b73166170 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Laat die program toe om jou fotoversameling te wysig."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lees liggings in jou mediaversameling"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Laat die program toe om liggings in jou mediaversameling te lees."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Gebruik biometrie"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gebruik biometrie of skermslot"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifieer dat dit jy is"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Gebruik jou biometrie om voort te gaan"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometriese hardeware is nie beskikbaar nie"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Stawing is gekanselleer"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Nie herken nie"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Stawing is gekanselleer"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Geen PIN, patroon of wagwoord is gestel nie"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Kon nie staaf nie"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Gebruik skermslot"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Voer jou toesteleiebewys in om voort te gaan."</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Gedeeltelike vingerafdruk is bespeur. Probeer asseblief weer."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Kon nie vingerafdruk verwerk nie. Probeer asseblief weer."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Vingerafdruksensor is vuil. Maak dit skoon en probeer weer."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Hierdie toetstel het nie \'n vingerafdruksensor nie."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor is tydelik gedeaktiveer."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gebruik vingerafdruk"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gebruik vingerafdruk of skermslot"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gebruik jou vingerafdruk om voort te gaan"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Gesigslot word nie op hierdie toestel gesteun nie."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor is tydelik gedeaktiveer."</string> <string name="face_name_template" msgid="3877037340223318119">"Gesig <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Gebruik gesigslot"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gebruik gesig- of skermslot"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Gebruik gesigslot om voort te gaan"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Gesig-ikoon"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Nuus en tydskrifte"</string> <string name="app_category_maps" msgid="6395725487922533156">"Kaarte en navigasie"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktiwiteit"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Toeganklikheid"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Toestelberging"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-ontfouting"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"uur"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index eb98c69b92be..254ca9cfad36 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"መተግበሪያው የፎቶ ስብስብዎን እንዲቀይረው ያስችለዋል።"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"አካባቢዎችን ከሚዲያ ስብስብዎ ማንበብ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"መተግበሪያው አካባቢዎችን ከሚዲያ ስብስብዎ እንዲያነብብ ያስችለዋል።"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"ባዮሜትሪኮችን ይጠቀሙ"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ባዮሜትሪክስ ወይም ማያ ገጽ መቆለፊያን ይጠቀሙ"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"እርስዎን መሆንዎን ያረጋግጡ"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ለመቀጠል ባዮሜትሪክዎን ይጠቀሙ"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ባዮሜትራዊ ሃርድዌር አይገኝም"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"ማረጋገጥ ተሰርዟል"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"አልታወቀም"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"ማረጋገጥ ተሰርዟል"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ምንም ፒን፣ ሥርዓተ ጥለት ወይም የይለፍ ቃል አልተቀናበረም"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"ማረጋገጥ ላይ ስህተት"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"የማያ ገጽ መቆለፊን ይጠቀሙ"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"ለመቀጠል የመሣሪያዎን የመግቢያ ማስረጃ ያስገቡ"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ከፊል የጣት አሻራ ተገኝቷል። እባክዎ እንደገና ይሞክሩ።"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ጣት አሻራን መስራት አልተቻለም። እባክዎ እንደገና ይሞክሩ።"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"የጣት አሻራ ዳሳሽ ቆሽሿል። እባክዎ ያጽዱት እና እንደገና ይሞክሩ።"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ይህ መሣሪያ የጣት አሻራ ዳሳሽ የለውም።"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ዳሳሽ ለጊዜው ተሰናክሏል።"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ጣት <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"የጣት አሻራ ይጠቀሙ"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"የጣት አሻራ ወይም የማያ ገጽ መቆለፊያ ይጠቀሙ"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ለመቀጠል የእርስዎን የጣት አሻራ ይጠቀሙ"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"በመልክ መክፈት መስጫ በዚህ መሣሪያ ላይ አይደገፍም።"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"ዳሳሽ ለጊዜው ተሰናክሏል።"</string> <string name="face_name_template" msgid="3877037340223318119">"ፊት <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"በመልክ መክፈትን ይጠቀሙ"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"የመልክ ወይም የማያ ገጽ መቆለፊያን ይጠቀሙ"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"ለመቀጠል በመልክ መክፈትን ይጠቀሙ"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"የፊት አዶ"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"ዜና እና መጽሔቶች"</string> <string name="app_category_maps" msgid="6395725487922533156">"ካርታዎች እና ዳሰሳ"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ውጤታማነት"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"ተደራሽነት"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"የመሣሪያ ማከማቻ"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"የዩኤስቢ ማረሚያ"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ሰዓት"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index d6759b6453b8..89ed573fd1f0 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -562,23 +562,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"للسماح للتطبيق بتعديل مجموعة صورك."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"قراءة المواقع من مجموعة الوسائط التابعة لك"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"للسماح للتطبيق بقراءة المواقع من مجموعة الوسائط التابعة لك."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"استخدام المقاييس الحيوية"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"استخدام المقاييس الحيوية أو قفل الشاشة"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"إثبات هويتك"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"استخدام المقاييس الحيوية للمتابعة"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"معدّات المقاييس الحيوية غير متاحة."</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"تم إلغاء المصادقة."</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"لم يتم التعرف عليها."</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"تم إلغاء المصادقة."</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"لم يتم ضبط رقم تعريف شخصي أو نقش أو كلمة مرور."</string> <string name="biometric_error_generic" msgid="6784371929985434439">"خطأ في المصادقة"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"استخدام قفل الشاشة"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"إدخال بيانات اعتماد الجهاز للمتابعة"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"تم اكتشاف جزء من بصمة الإصبع فقط؛ يرجى إعادة المحاولة."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"تعذرت معالجة بصمة الإصبع. يُرجى إعادة المحاولة."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"زر استشعار بصمات الأصابع متّسخ. يُرجى تنظيفه وإعادة المحاولة."</string> @@ -601,10 +596,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"لا يحتوي هذا الجهاز على مستشعِر بصمات إصبع."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"تم إيقاف جهاز الاستشعار مؤقتًا."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"الإصبع <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"استخدام بصمة الإصبع"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"استخدام بصمة الإصبع أو قفل الشاشة"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"يمكنك استخدام بصمة الإصبع للمتابعة."</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -650,12 +643,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"\"فتح القفل بالوجه\" غير متوفر على هذا الجهاز."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"تم إيقاف جهاز الاستشعار مؤقتًا."</string> <string name="face_name_template" msgid="3877037340223318119">"الوجه <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"استخدام ميزة \"فتح القفل بالوجه\""</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"استخدام ميزة \"فتح القفل بالوجه\" أو ميزة \"قفل الشاشة\""</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"استخدام ميزة \"فتح القفل بالوجه\" للمتابعة"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"رمز الوجه"</string> @@ -2018,7 +2008,7 @@ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"تنبيه بشأن تصيّد احتيالي"</string> <string name="notification_work_profile_content_description" msgid="5296477955677725799">"الملف الشخصي للعمل"</string> <string name="notification_alerted_content_description" msgid="6139691253611265992">"تمّ تفعيل التنبيه"</string> - <string name="notification_verified_content_description" msgid="6401483602782359391">"تم التحقّق"</string> + <string name="notification_verified_content_description" msgid="6401483602782359391">"تم التحقّق من المتّصل"</string> <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"توسيع"</string> <string name="expand_button_content_description_expanded" msgid="7484217944948667489">"تصغير"</string> <string name="expand_action_accessibility" msgid="1947657036871746627">"تبديل التوسيع"</string> @@ -2094,8 +2084,7 @@ <string name="app_category_news" msgid="1172762719574964544">"الأخبار والمجلات"</string> <string name="app_category_maps" msgid="6395725487922533156">"الخرائط والتنقل"</string> <string name="app_category_productivity" msgid="1844422703029557883">"الإنتاجية"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"أدوات تمكين الوصول"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"مساحة التخزين للجهاز"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"تصحيح أخطاء USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ساعة"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 0a4c397de8c3..67d2ce05a348 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"এপক আপোনাৰ ফট’ সংগ্ৰহ সালসলনি কৰিবলৈ দিয়ে।"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"এপক আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ দিয়ে।"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"বায়\'মেট্ৰিক ব্যৱহাৰ কৰক"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"বায়\'মেট্ৰিক অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"এইয়া আপুনিয়েই বুলি সত্যাপন কৰক"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"অব্যাহত ৰাখিবলৈ আপোনাৰ বায়\'মেট্ৰিক ব্যৱহাৰ কৰক"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"বায়োমেট্ৰিক হাৰ্ডৱেৰ উপলব্ধ নহয়"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"বিশ্বাসযোগ্যতাৰ প্ৰমাণীকৰণ বাতিল কৰা হৈছে"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"চিনাক্ত কৰিব পৰা নাই"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"বিশ্বাসযোগ্যতাৰ প্ৰমাণীকৰণ বাতিল কৰা হৈছে"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"কোনো পিন, আৰ্হি বা পাছৱৰ্ড ছেট কৰা নাই"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"আসোঁৱাহৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰি থকা হৈছে"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"স্ক্ৰীন ল\'ক ব্যৱহাৰ কৰক"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"অব্যাহত ৰাখিবলৈ আপোনাৰ ডিভাইচৰ ক্ৰেডেনশ্বিয়েল দিয়ক"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ফিংগাৰপ্ৰিণ্ট আংশিকভাৱে চিনাক্ত কৰা হৈছে। অনুগ্ৰহ কৰি আকৌ চেষ্টা কৰক৷"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ফিগাৰপ্ৰিণ্টৰ প্ৰক্ৰিয়া সম্পাদন কৰিবপৰা নগ\'ল। অনুগ্ৰহ কৰি আকৌ চেষ্টা কৰক৷"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো লেতেৰা হৈ আছে। অনুগ্ৰহ কৰি পৰিষ্কাৰ কৰি আকৌ চেষ্টা কৰক।"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইচটোত ফিংগাৰপ্ৰিণ্ট ছেন্সৰ নাই।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> আঙুলি"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ফিংগাৰপ্ৰিণ্ট অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"অব্যাহত ৰাখিবলৈ আপোনাৰ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"এই ডিভাইচটোত মুখাৱয়বৰদ্বাৰা আনলক কৰা সুবিধাটো নচলে।"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string> <string name="face_name_template" msgid="3877037340223318119">"মুখমণ্ডল <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"মুখাৱয়বৰে আনলক কৰা ব্যৱহাৰ কৰক"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"মুখাৱয়বৰে আনলক কৰা অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"অব্যাহত ৰাখিবলৈ মুখাৱয়বৰে আনলক কৰা ব্যৱহাৰ কৰক"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"মুখমণ্ডলৰ আইকন"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"বাতৰি আৰু আলোচনী"</string> <string name="app_category_maps" msgid="6395725487922533156">"মেপ আৰু দিক্-নিৰ্দেশনা"</string> <string name="app_category_productivity" msgid="1844422703029557883">"উৎপাদনশীলতা"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"সাধ্য সুবিধা"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ডিভাইচৰ সঞ্চয়াগাৰ"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"ইউএছবি ডিবাগিং"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ঘণ্টা"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index afb5c397dde5..76b5f1b9aded 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Tətbiqin foto kolleksiyanıza düzəliş etməsinə icazə verir."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"media kolleksiyanızdan məkanları oxuyun"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Tətbiqin media kolleksiyanızdan məkanları oxumasına icazə verin."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometrik məlumatlardan istifadə edin"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrik məlumatlardan və ya ekran kilidindən istifadə edin"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Kimliyinizi doğrulayın"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Davam etmək üçün biometrik məlumatlarınızdan istifadə edin"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrik proqram əlçatan deyil"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Doğrulama ləğv edildi"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Tanınmır"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Doğrulama ləğv edildi"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pin, nümunə və ya parol ayarlanmayıb"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Doğrulama zamanı xəta baş verdi"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ekran kilidindən istifadə edin"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Davam etmək üçün cihazın giriş məlumatlarını daxil edin"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Barmaq izi yarımçıq müəyyən olundu. Lütfən, yenidən cəhd edin."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Barmaq izi tanınmadı. Lütfən, yenidən cəhd edin."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Barmaq izi sensoru çirklidir. Lütfən, təmizləyin və yenidən cəhd edin."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda barmaq izi sensoru yoxdur."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor müvəqqəti deaktivdir."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Barmaq <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Barmaq izindən istifadə edin"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Barmaq izi və ya ekran kilidindən istifadə edin"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Davam etmək üçün barmaq izinizi istifadə edin"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Üz kilidi bu cihazda dəstəklənmir."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor müvəqqəti deaktivdir."</string> <string name="face_name_template" msgid="3877037340223318119">"Üz <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Üz ilə kiliddən çıxarmadan istifadə edin"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Üz və ya ekran kilidindən istifadə edin"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Davam etmək üçün üz ilə kiliddən çıxarmadan istifadə edin"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Üz işarəsi"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Xəbər və Jurnallar"</string> <string name="app_category_maps" msgid="6395725487922533156">"Xəritə və Naviqasiya"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Məhsuldarlıq"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Əlçatımlılıq"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Cihaz yaddaşı"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB sazlama"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"saat"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 0d23fa56d55b..97781c7849a9 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -553,23 +553,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Dozvoljava aplikaciji da menja kolekciju slika."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"čitanje lokacija iz medijske kolekcije"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Dozvoljava aplikaciji da čita lokacije iz medijske kolekcije."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Koristite biometriju"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Koristite biometriju ili zaključavanje ekrana"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite svoj identitet"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Koristite biometrijski podatak da biste nastavili"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Potvrda identiteta je otkazana"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Nije prepoznato"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Potvrda identiteta je otkazana"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Niste podesili ni PIN, ni šablon, ni lozinku"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Greška pri potvrdi identiteta"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Koristite zaključavanje ekrana"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Unesite akreditiv za uređaj da biste nastavili"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Otkriven je delimični otisak prsta. Probajte ponovo."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nije uspela obrada otiska prsta. Probajte ponovo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzor za otiske prstiju je prljav. Očistite ga i pokušajte ponovo."</string> @@ -592,10 +587,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Koristite otisak prsta"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Koristite otisak prsta ili zaključavanje ekrana"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Nastavite pomoću otiska prsta"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -641,12 +634,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string> <string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Koristite otključavanje licem"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Koristite zaključavanje licem ili zaključavanje ekrana"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Koristite otključavanje licem da biste nastavili"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string> @@ -1998,8 +1988,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Novosti i časopisi"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mape i navigacija"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktivnost"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Pristupačnost"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Memorijski prostor uređaja"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Otklanjanje grešaka sa USB-a"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"sat"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 87b4ce7faa5a..32672472f145 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -556,23 +556,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Праграма зможа змяняць фотакалекцыю."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"паказваць месцазнаходжанне ў калекцыі мультымедыя"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Праграма зможа паказваць месцазнаходжанне ў калекцыі мультымедыя."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Выкарыстоўваць біяметрыю"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Выкарыстоўваць біяметрыю ці блакіроўку экрана"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Спраўдзіце, што гэта вы"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Каб працягнуць, скарыстайце свае біяметрычныя даныя"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Біяметрычнае абсталяванне недаступнае"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аўтэнтыфікацыя скасавана"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Не распазнана"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Аўтэнтыфікацыя скасавана"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Не заданы PIN-код, узор разблакіроўкі або пароль"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Памылка аўтэнтыфікацыі"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ужываць блакіроўку экрана"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Каб працягнуць, увядзіце ўліковыя даныя вашай прылады"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Адсканіравана толькі частка адбітка пальца. Паспрабуйце яшчэ раз."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Не атрымалася апрацаваць адбітак пальца. Паспрабуйце яшчэ раз."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Сканер адбіткаў пальцаў брудны. Ачысціце яго і паспрабуйце яшчэ раз."</string> @@ -595,10 +590,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На гэтай прыладзе няма сканера адбіткаў пальцаў."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчык часова выключаны."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Палец <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Выкарыстоўваць адбітак пальца"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Выкарыстоўваць адбітак пальца ці блакіроўку экрана"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Каб працягнуць, выкарыстоўвайце свой адбітак пальца"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -644,12 +637,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"На гэтай прыладзе распазнаванне твару не падтрымліваецца."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Датчык часова выключаны."</string> <string name="face_name_template" msgid="3877037340223318119">"Твар <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Ужываць распазнаванне твару"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Выкарыстоўваць распазнаванне твару ці блакіроўку экрана"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Каб працягнуць, скарыстайце распазнаванне твару"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Значок твару"</string> @@ -2030,8 +2020,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Навіны і часопісы"</string> <string name="app_category_maps" msgid="6395725487922533156">"Карты і навігацыя"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Прадукцыйнасць"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Спецыяльныя магчымасці"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Сховішча на прыладзе"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Адладка USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"гадз"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 7e847e0a66af..ac55c913a64e 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Разрешава на приложението да променя колекцията ви от снимки."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"да чете местоположенията от мултимедийната ви колекция"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Разрешава на приложението да чете местоположенията от мултимедийната ви колекция."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Използване на биометр. данни"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Използване на биометрични данни или опцията за заключване на екрана"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Потвърдете, че сте вие"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Използвайте биометричните си данни, за да продължите"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометричният хардуер не е налице"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Удостоверяването бе анулирано"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Не е разпознато"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Удостоверяването бе анулирано"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Няма зададен ПИН код, фигура или парола"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Грешка при удостоверяването"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ползване на заключв. на екрана"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Въведете идентификационните данни на устройството, за да продължите"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Открит е частичен отпечатък. Моля, опитайте отново."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Отпечатъкът не бе обработен. Моля, опитайте отново."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Сензорът за отпечатъци е мръсен. Моля, почистете го и опитайте отново."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Това устройство няма сензор за отпечатъци."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорът е временно деактивиран."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Пръст <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Използване на отпечатък"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Използване на отпечатък или опцията за заключване на екрана"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Използвайте отпечатъка си, за да продължите"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Отключването с лице не се поддържа на това устройство."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Сензорът е временно деактивиран."</string> <string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Използване на отключв. с лице"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Използване на отключването с лице или опцията за заключване на екрана"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Използвайте функцията за отключване с лице, за да продължите"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Икона на лице"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Новини и списания"</string> <string name="app_category_maps" msgid="6395725487922533156">"Карти и навигация"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Производителност"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Достъпност"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Хранилище на устройството"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Отстраняване на грешки през USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"час"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 4d3d79394521..ff25441fbe7d 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"অ্যাপকে আপনার ফটো সংগ্রহ পরিবর্তন করার অনুমতি দিন।"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ডিয়া সংগ্রহ থেকে লোকেশন দেখতে দিন"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"আপনার মিডিয়া সংগ্রহ থেকে লোকেশন দেখতে অ্যাপকে অনুমতি দিন।"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"বায়োমেট্রিক্স ব্যবহার করুন"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"বায়োমেট্রিক্স অথবা স্ক্রিন লক ব্যবহার করুন"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"আপনার পরিচয় যাচাই করুন"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"চালিয়ে যেতে আপনার বায়োমেট্রিক্স ব্যবহার করুন"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"বায়োমেট্রিক হার্ডওয়্যার পাওয়া যাবে না"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"যাচাইকরণ বাতিল হয়েছে"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"স্বীকৃত নয়"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"যাচাইকরণ বাতিল হয়েছে"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"পিন, প্যাটার্ন অথবা পাসওয়ার্ড সেট করা নেই"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"যাচাইকরণে সমস্যা হয়েছে"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"স্ক্রিন লক ব্যবহার করুন"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"চালিয়ে যেতে আপনার ডিভাইসের ক্রেডেনশিয়াল ব্যবহার করুন"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"আঙ্গুলের ছাপ আংশিক শনাক্ত করা হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"আঙ্গুলের ছাপ প্রক্রিয়া করা যায়নি৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"আঙ্গুলের ছাপ নেওয়ার সেন্সরটি অপরিস্কার৷ পরিষ্কার করে আবার চেষ্টা করুন৷"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইসে আঙ্গুলের ছাপ নেওয়ার সেন্সর নেই।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"সেন্সর অস্থায়ীভাবে বন্ধ করা আছে।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"আঙ্গুল <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"আঙ্গুলের ছাপ ব্যবহার করুন"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"আঙ্গুলের ছাপ অথবা স্ক্রিন লক ব্যবহার করুন"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"চালিয়ে যেতে আঙ্গুলের ছাপ ব্যবহার করুন"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"এই ডিভাইসে মুখের সাহায্যে আনলক করার সুবিধাটি কাজ করে না।"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"সেন্সর অস্থায়ীভাবে বন্ধ করা আছে।"</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> ফেস"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"মুখের সাহায্যে আনলক ব্যবহার করুন"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"মুখ অথবা স্ক্রিন লক ব্যবহার করুন"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"চালিয়ে যেতে মুখের সাহায্যে আনলক ব্যবহার করুন"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"ফেস আইকন"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"খবর ও পত্রিকাগুলি"</string> <string name="app_category_maps" msgid="6395725487922533156">"ম্যাপ ও নেভিগেশান"</string> <string name="app_category_productivity" msgid="1844422703029557883">"উৎপাদনশীলতা"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"অ্যাক্সেসিবিলিটি"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ডিভাইসের স্টোরেজ"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ডিবাগিং"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ঘণ্টা"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 2e24175bbaa4..25129e489a05 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -553,23 +553,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Omogućava aplikaciji da mijenja vašu kolekciju fotografija."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"čitanje lokacija iz kolekcije medija"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Omogućava aplikaciji da čita lokacije iz vaše kolekcije medija."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Koristi biometriju"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Koristi biometriju ili zaključavanje ekrana"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite identitet"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Koristite biometriju da nastavite"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikacija je otkazana"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Nije prepoznato"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikacija je otkazana"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nije postavljen PIN, uzorak niti lozinka"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Greška pri autentifikaciji"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Koristi zaključavanje ekrana"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Unesite akreditiv uređaja da nastavite"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Otkriven je djelimični otisak prsta. Pokušajte ponovo."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Obrada otiska prsta nije uspjela. Pokušajte ponovo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzor za otisak prsta je prljav. Očistite ga i pokušajte ponovo."</string> @@ -592,10 +587,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Koristi otisak prsta"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Koristi otisak prsta ili zaključavanje ekrana"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Nastavite pomoću otiska prsta"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -641,12 +634,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string> <string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Koristi otključavanje licem"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Koristi otključavanje licem ili zaključavanje ekrana"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Koristite otključavanje licem da nastavite"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string> @@ -1998,8 +1988,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Vijesti i časopisi"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mape i navigacija"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktivnost"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Pristupačnost"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Memorija uređaja"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Otklanjanje grešaka putem USB-a"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"sat"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 70caa2cff7fe..6f2af9203553 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permet que l\'aplicació modifiqui la teva col·lecció de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"llegir les ubicacions de les teves col·leccions multimèdia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permet que l\'aplicació llegeixi les ubicacions de les teves col·leccions multimèdia."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utilitza la biometria"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Fes servir la biometria o el bloqueig de pantalla"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que ets tu"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilitza la teva biometria per continuar"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Maquinari biomètric no disponible"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"S\'ha cancel·lat l\'autenticació"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"No s\'ha reconegut"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"S\'ha cancel·lat l\'autenticació"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No s\'ha definit cap PIN, patró o contrasenya"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Error en l\'autenticació"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Utilitza el bloqueig de pantalla"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Utilitza les credencials del teu dispositiu per continuar"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"S\'ha detectat una empremta digital parcial. Torna-ho a provar."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No s\'ha pogut processar l\'empremta digital. Torna-ho a provar."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"El sensor d\'empremtes dactilars està brut. Neteja\'l i torna-ho a provar."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aquest dispositiu no té sensor d\'empremtes dactilars."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor està desactivat temporalment."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dit <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilitza l\'empremta digital"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilitza l\'empremta digital o el bloqueig de pantalla"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Fes servir l\'empremta digital per continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"El desbloqueig facial no és compatible amb el dispositiu."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"El sensor està desactivat temporalment."</string> <string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Utilitza el desbloqueig facial"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Utilitza el desbloqueig facial o de pantalla"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Utilitza el desbloqueig facial per continuar"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Icona facial"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Notícies i revistes"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mapes i navegació"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productivitat"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accessibilitat"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Emmagatzematge del dispositiu"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuració per USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 0f732669f467..bd9866279e96 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -556,23 +556,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Umožňuje aplikaci upravit vaši sbírku fotek."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"čtení míst ze sbírky médií"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Umožňuje aplikaci číst místa z vaší sbírky médií."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Použít biometrii"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Použít biometrii nebo zámek obrazovky"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrďte, že jste to vy"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Pokračujte biometrickým ověřením"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrický hardware není k dispozici"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ověření bylo zrušeno"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Nerozpoznáno"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Ověření bylo zrušeno"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Není nastaven žádný PIN, gesto ani heslo"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Při ověřování došlo k chybě"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Použít zámek obrazovky"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Pokračujte zadáním identifikačních úřadů svého zařízení"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Byla zjištěna jen část otisku prstu. Zkuste to znovu."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Zpracování otisku prstu se nezdařilo. Zkuste to znovu."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzor otisků prstů je znečištěn. Vyčistěte jej a zkuste to znovu."</string> @@ -595,10 +590,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zařízení nemá snímač otisků prstů."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasně deaktivován."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Použít otisk prstu"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Použít otisk prstu nebo zámek obrazovky"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Pokračujte přiložením prstu"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -644,12 +637,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Odemknutí obličejem na tomto zařízení není podporováno."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je dočasně deaktivován."</string> <string name="face_name_template" msgid="3877037340223318119">"Obličej <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Použít odemknutí obličejem"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Použít odemknutí obličejem nebo zámek obrazovky"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Pokračujte odemknutím obličejem"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona obličeje"</string> @@ -2030,8 +2020,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Zprávy a časopisy"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mapy a navigace"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktivita"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Přístupnost"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Úložiště zařízení"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Ladění přes USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hodina"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 13afaf251317..70492e01fc1b 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -552,23 +552,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Tillader, at appen kan ændre din billedsamling."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"læse placeringer fra din mediesamling"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Tillader, at appen kan læse placeringer fra din mediesamling."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Brug biometriske systemer"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Brug biometriske systemer eller skærmlås"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Bekræft, at det er dig"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Brug dine biometriske data for at fortsætte"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk hardware er ikke tilgængelig"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Godkendelsen blev annulleret"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Ikke genkendt"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Godkendelsen blev annulleret"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Der er ikke angivet pinkode, mønster eller adgangskode"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Der opstod fejl i forbindelse med godkendelse"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Brug skærmlås"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Angiv dine loginoplysninger for enheden for at fortsætte"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Der blev registreret et delvist fingeraftryk. Prøv igen."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Fingeraftrykket kunne ikke behandles. Prøv igen."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingeraftrykslæseren er beskidt. Tør den af, og prøv igen."</string> @@ -591,10 +586,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enhed har ingen fingeraftrykslæser."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidigt deaktiveret."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Fingeraftryk <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Brug fingeraftryk"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Brug fingeraftryk eller skærmlås"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Brug dit fingeraftryk for at fortsætte"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -640,12 +633,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansigtslås understøttes ikke på denne enhed."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensoren er midlertidigt deaktiveret."</string> <string name="face_name_template" msgid="3877037340223318119">"Ansigt <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Brug ansigtslås"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Brug ansigts- eller skærmlås"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Brug ansigtslås for at fortsætte"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ansigt"</string> @@ -1968,8 +1958,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Aviser og blade"</string> <string name="app_category_maps" msgid="6395725487922533156">"Kort og navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktivitet"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Hjælpefunktioner"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Lagerplads på enheden"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-fejlretning"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"time"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 512b3a555eec..6e458fa30fd5 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Ermöglicht der App, deine Fotosammlung zu ändern."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"Standorte aus meiner Mediensammlung abrufen"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Ermöglicht der App, Standorte aus deiner Mediensammlung abzurufen."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometrisches Verfahren nutzen"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrisches Verfahren oder Displaysperre verwenden"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Deine Identität bestätigen"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Mithilfe eines biometrischen Verfahrens fortfahren"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrische Hardware nicht verfügbar"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentifizierung abgebrochen"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Nicht erkannt"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Authentifizierung abgebrochen"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Keine PIN, kein Muster und kein Passwort festgelegt"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Fehler bei der Authentifizierung"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Displaysperre verwenden"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Zum Fortfahren Anmeldedaten des Geräts eingeben"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Fingerabdruck nur teilweise erkannt. Bitte versuche es noch einmal."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Fingerabdruck konnte nicht verarbeitet werden. Bitte versuche es noch einmal."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerabdrucksensor ist verschmutzt. Reinige ihn und versuche es noch einmal."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dieses Gerät hat keinen Fingerabdrucksensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Der Sensor ist vorübergehend deaktiviert."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Fingerabdruck verwenden"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Fingerabdruck oder Displaysperre verwenden"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Mithilfe deines Fingerabdrucks fortfahren"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock wird auf diesem Gerät nicht unterstützt."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Der Sensor ist vorübergehend deaktiviert."</string> <string name="face_name_template" msgid="3877037340223318119">"Gesicht <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Face Unlock verwenden"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Face Unlock oder Displaysperre verwenden"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Zum Fortfahren Face Unlock verwenden"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Gesichtssymbol"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Nachrichten & Zeitschriften"</string> <string name="app_category_maps" msgid="6395725487922533156">"Karten & Navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Effizienz"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Bedienungshilfen"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Gerätespeicher"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-Fehlerbehebung"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"Stunde"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index d9dc2c55cb09..920f09eb777d 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Επιτρέπει στην εφαρμογή να τροποποιήσει τη συλλογή φωτογραφιών σας."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ανάγνωση τοποθεσιών από τη συλλογή πολυμέσων σας"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Επιτρέπει στην εφαρμογή να διαβάσει τοποθεσίες από τη συλλογή πολυμέσων σας."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Χρήση βιομετρικών"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Χρήση βιομετρικών ή κλειδώματος οθόνης"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Επαλήθευση ταυτότητας"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Χρησιμοποιήστε βιομετρικά για να συνεχίσετε"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Δεν υπάρχει διαθέσιμος βιομετρικός εξοπλισμός"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ο έλεγχος ταυτότητας ακυρώθηκε"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Δεν αναγνωρίστηκε"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Ο έλεγχος ταυτότητας ακυρώθηκε"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Δεν έχει οριστεί PIN, μοτίβο ή κωδικός πρόσβασης"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Σφάλμα κατά τον έλεγχο ταυτότητας"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Χρήση κλειδώματος οθόνης"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Εισαγάγετε το διαπιστευτήριο της συσκευής σας για να συνεχίσετε"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Εντοπίστηκε μόνο μέρος του δακτυλικού αποτυπώματος. Δοκιμάστε ξανά."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Δεν ήταν δυνατή η επεξεργασία του δακτυλικού αποτυπώματος. Δοκιμάστε ξανά."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Ο αισθητήρας δακτυλικού αποτυπώματος δεν είναι καθαρός. Καθαρίστε τον και δοκιμάστε ξανά."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Αυτή η συσκευή δεν διαθέτει αισθητήρα δακτυλικού αποτυπώματος."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Ο αισθητήρας απενεργοποιήθηκε προσωρινά."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Δάχτυλο <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Χρήση δακτυλικού αποτυπώματος"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Χρήση δακτυλικού αποτυπώματος ή κλειδώματος οθόνης"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Χρησιμοποιήστε το δακτυλικό αποτύπωμά σας για να συνεχίσετε"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Το Face Unlock δεν υποστηρίζεται σε αυτήν τη συσκευή."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Ο αισθητήρας απενεργοποιήθηκε προσωρινά."</string> <string name="face_name_template" msgid="3877037340223318119">"Πρόσωπο <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Χρήση Face Unlock"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Χρήση προσώπου ή κλειδώματος οθόνης"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Χρησιμοποιήστε το Face Unlock για να συνεχίσετε"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Εικ. προσ."</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Ειδήσεις και περιοδικά"</string> <string name="app_category_maps" msgid="6395725487922533156">"Χάρτες και πλοήγηση"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Παραγωγικότητα"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Προσβασιμότητα"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Αποθηκευτικός χώρος συσκευής"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Εντοπισμός σφαλμάτων USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ώρα"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 73e2ca0d3fe5..43a7fb6662d6 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Use biometrics"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use your biometric to continue"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognised"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication cancelled"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern or password set"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Error while authenticating"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Use screen lock"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Enter your device credential to continue"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Partial fingerprint detected. Please try again."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerprint sensor is dirty. Please clean and try again."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string> <string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Use face unlock"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Use face unlock to continue"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"News & Magazines"</string> <string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productivity"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accessibility"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Device storage"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB debugging"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hour"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 67130e1fb5c5..04390c74bb32 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Use biometrics"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use your biometric to continue"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognised"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication cancelled"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern or password set"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Error while authenticating"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Use screen lock"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Enter your device credential to continue"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Partial fingerprint detected. Please try again."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerprint sensor is dirty. Please clean and try again."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string> <string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Use face unlock"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Use face unlock to continue"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"News & Magazines"</string> <string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productivity"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accessibility"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Device storage"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB debugging"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hour"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 1d36494b7b8b..84224ed85d10 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Use biometrics"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use your biometric to continue"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognised"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication cancelled"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern or password set"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Error while authenticating"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Use screen lock"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Enter your device credential to continue"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Partial fingerprint detected. Please try again."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerprint sensor is dirty. Please clean and try again."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string> <string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Use face unlock"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Use face unlock to continue"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"News & Magazines"</string> <string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productivity"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accessibility"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Device storage"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB debugging"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hour"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 016c55c3352c..d740e01c502e 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Use biometrics"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use your biometric to continue"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognised"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication cancelled"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern or password set"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Error while authenticating"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Use screen lock"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Enter your device credential to continue"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Partial fingerprint detected. Please try again."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerprint sensor is dirty. Please clean and try again."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string> <string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Use face unlock"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Use face unlock to continue"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"News & Magazines"</string> <string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productivity"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accessibility"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Device storage"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB debugging"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hour"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index bd7da803e42b..6125c167fa7d 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que la app modifique tu colección de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"leer ubicaciones de tu colección de contenido multimedia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que la app lea las ubicaciones de tu colección de contenido multimedia."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usar datos biométricos"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar datos biométricos o bloqueo de pantalla"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Comprueba que eres tú"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Usa tus datos biométricos para continuar"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"No hay hardware biométrico disponible"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Se canceló la autenticación"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"No se reconoció"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Se canceló la autenticación"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No se estableció ningún PIN, patrón ni contraseña"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Error de autenticación"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar bloqueo de pantalla"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Ingresa las credenciales de tu dispositivo para continuar"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Se detectó parcialmente la huella dactilar. Vuelve a intentarlo."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No se pudo procesar la huella dactilar. Vuelve a intentarlo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"El sensor de huellas dactilares está sucio. Limpia el sensor y vuelve a intentarlo."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas dactilares."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Se inhabilitó temporalmente el sensor."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar huella digital"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar bloqueo de huella dactilar o pantalla"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utiliza tu huella dactilar para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"No se admite el desbloqueo facial en este dispositivo."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Se inhabilitó temporalmente el sensor."</string> <string name="face_name_template" msgid="3877037340223318119">"Rostro <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Usar desbloqueo facial"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usar bloqueo facial o de pantalla"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Usa el desbloqueo facial para continuar"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ícono cara"</string> @@ -1576,8 +1566,8 @@ <string name="expires_on" msgid="1623640879705103121">"Expira el:"</string> <string name="serial_number" msgid="3479576915806623429">"Número de serie:"</string> <string name="fingerprints" msgid="148690767172613723">"Huellas digitales:"</string> - <string name="sha256_fingerprint" msgid="7103976380961964600">"Huella dactilar SHA-256"</string> - <string name="sha1_fingerprint" msgid="2339915142825390774">"Huella dactilar SHA-1:"</string> + <string name="sha256_fingerprint" msgid="7103976380961964600">"Huella digital SHA-256"</string> + <string name="sha1_fingerprint" msgid="2339915142825390774">"Huella digital SHA-1:"</string> <string name="activity_chooser_view_see_all" msgid="3917045206812726099">"Ver todas"</string> <string name="activity_chooser_view_dialog_title_default" msgid="8880731437191978314">"Elige actividad"</string> <string name="share_action_provider_share_with" msgid="1904096863622941880">"Compartir con"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Noticias y revistas"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mapas y navegación"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productividad"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accesibilidad"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Almacenamiento del dispositivo"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuración por USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index d771977431c3..0e163d2b263b 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que la aplicación modifique tu colección de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"leer las ubicaciones de tu colección de contenido multimedia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que la aplicación lea las ubicaciones de tu colección de contenido multimedia."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usar biometría"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar biometría o bloqueo de pantalla"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que eres tú"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Usa tu biometría para continuar"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico no disponible"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticación cancelada"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"No se reconoce"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticación cancelada"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No se ha definido el PIN, el patrón o la contraseña"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"No se ha podido autenticar"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar bloqueo de pantalla"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Introduce las credenciales del dispositivo para continuar"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Se ha detectado una huella digital parcial. Vuelve a intentarlo."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No se ha podido procesar la huella digital. Vuelve a intentarlo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"El sensor de huellas digitales está sucio. Límpialo y vuelve a intentarlo."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas digitales."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor está inhabilitado en estos momentos."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar huella digital"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar huella digital o bloqueo de pantalla"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Usa tu huella digital para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"El desbloqueo facial no está disponible en este dispositivo."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"El sensor está inhabilitado en estos momentos."</string> <string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Usar desbloqueo facial"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usar desbloqueo facial o bloqueo de pantalla"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Usa el desbloqueo facial para continuar"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Icono cara"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Noticias y revistas"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mapas y navegación"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productividad"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accesibilidad"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Almacenamiento del dispositivo"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuración por USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index ec02fad6683c..9f6df6e8ff35 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Võimaldab rakendusel muuta teie fotokogu."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"Lugeda teie meediakogus olevaid asukohti"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Võimaldab rakendusel lugeda teie meediakogus olevaid asukohti."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biomeetria kasutamine"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biomeetria või ekraaniluku kasutamine"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Kinnitage oma isik"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Jätkamiseks kasutage biomeetriat"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biomeetriline riistvara ei ole saadaval"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentimine tühistati"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Ei tuvastatud"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentimine tühistati"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-koodi, mustrit ega parooli pole määratud"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Viga autentimisel"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ekraaniluku kasutamine"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Jätkamiseks sisestage seadme mandaat"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Tuvastati osaline sõrmejälg. Proovige uuesti."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Sõrmejälge ei õnnestunud töödelda. Proovige uuesti."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Sõrmejäljeandur on must. Puhastage see ja proovige uuesti."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Selles seadmes pole sõrmejäljeandurit."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Andur on ajutiselt keelatud."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Sõrmejälg <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Sõrmejälje kasutamine"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Sõrmejälje või ekraaniluku kasutamine"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Jätkamiseks kasutage sõrmejälge"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Seade ei toeta Face Unlocki."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Andur on ajutiselt keelatud."</string> <string name="face_name_template" msgid="3877037340223318119">"Nägu <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Face Unlocki kasutamine"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Face Unlocki või ekraaniluku kasutamine"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Jätkamiseks kasutage Face Unlocki"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Näoikoon"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Uudised ja ajakirjad"</string> <string name="app_category_maps" msgid="6395725487922533156">"Kaardid ja navigeerimine"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktiivsus"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Juurdepääsetavus"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Seadme salvestusruum"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB silumine"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"tund"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 8ee77a600739..72d083363594 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -313,8 +313,8 @@ <string name="permgroupdesc_storage" msgid="6351503740613026600">"atzitu gailuko argazkiak, multimedia-edukia eta fitxategiak"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofonoa"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"grabatu audioa"</string> - <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Ariketa fisikoa"</string> - <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"ariketa fisikoak atzitu"</string> + <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Jarduera fisiko"</string> + <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"jarduera fisikoa atzitu"</string> <string name="permgrouplab_camera" msgid="9090413408963547706">"Kamera"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"atera argazkiak eta grabatu bideoak"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"Deien erregistroa"</string> @@ -445,8 +445,8 @@ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Aplikazioak edonoiz erabil dezake mikrofonoa audioa grabatzeko."</string> <string name="permlab_sim_communication" msgid="176788115994050692">"bidali aginduak SIM txartelera"</string> <string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM txartelera aginduak bidaltzeko aukera ematen die aplikazioei. Oso arriskutsua da."</string> - <string name="permlab_activityRecognition" msgid="1782303296053990884">"hauteman ariketa fisikoa"</string> - <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Aplikazioak ariketa fisikoa hauteman dezake."</string> + <string name="permlab_activityRecognition" msgid="1782303296053990884">"hauteman jarduera fisiko"</string> + <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Aplikazioak jarduera fisiko hauteman dezake."</string> <string name="permlab_camera" msgid="6320282492904119413">"atera argazkiak eta grabatu bideoak"</string> <string name="permdesc_camera" msgid="5240801376168647151">"Aplikazioak abian den bitartean erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko."</string> <string name="permlab_backgroundCamera" msgid="7549917926079731681">"Argazkiak atera eta bideoak grabatu atzeko planoan."</string> @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Argazki-bilduma aldatzeko baimena ematen die aplikazioei."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"multimedia-edukien bildumako kokapena irakurri"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Multimedia-edukien bildumako kokapena irakurtzeko baimena ematen die aplikazioei."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Erabili sistema biometrikoak"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Erabili sistema biometrikoak edo pantailaren blokeoa"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Egiaztatu zeu zarela"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Aurrera egiteko, erabili sistema biometrikoak"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrikoa ez dago erabilgarri"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Utzi da autentifikazioa"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Ez da ezagutu"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Utzi egin da autentifikazioa"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ez da ezarri PIN koderik, eredurik edo pasahitzik"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Errorea autentifikatzean"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Erabili pantailaren blokeoa"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Aurrera egiteko, idatzi gailuaren kredentzialak"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Hatz-marka ez da osorik hauteman. Saiatu berriro."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Ezin izan da prozesatu hatz-marka. Saiatu berriro."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Hatz-marken sentsorea zikina dago. Garbi ezazu, eta saiatu berriro."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Gailu honek ez du hatz-marken sentsorerik."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sentsorea aldi baterako desgaitu da."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> hatza"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Erabili hatz-marka"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Erabili hatz-marka edo pantailaren blokeoa"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Aurrera egiteko, erabili hatz-marka"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Gailu honek ez du onartzen aurpegiaren bidez desblokeatzea."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sentsorea aldi baterako desgaitu da."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> aurpegia"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Erabili aurpegiaren bidez desblokeatzeko eginbidea"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Erabili aurpegia edo pantailaren blokeoa"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Aurrera egiteko, erabili aurpegiaren bidez desblokeatzeko eginbidea"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Aurpegiaren ikonoa"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Albisteak eta aldizkariak"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mapak eta nabigazioa"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktibitatea"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Erabilerraztasuna"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Gailuaren memoria"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB bidezko arazketa"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ordu"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 42b8c85f7eb9..76d0c1e794f9 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"به برنامه اجازه میدهد مجموعه عکستان را تغییر دهد."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"خواندن مکانها از مجموعه رسانه شما"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"به برنامه اجازه میدهد مکانها را از مجموعه رسانهتان بخواند."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"استفاده از زیستسنجشی"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"استفاده از زیستسنجشی یا قفل صفحه"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"تأیید کنید این شما هستید"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"برای ادامه، از زیستسنجشی استفاده کنید"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"سختافزار زیستسنجی دردسترس نیست"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"اصالتسنجی لغو شد"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"شناسایی نشد"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"اصالتسنجی لغو شد"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"پین، الگو یا گذرواژهای تنظیم نشده است"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"خطا هنگام اصالتسنجی"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"از قفل صفحه استفاده کنید"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"برای ادامه، اطلاعات کاربری دستگاهتان را وارد کنید"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"بخشی از اثر انگشت شناسایی شد. لطفاً دوباره امتحان کنید."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"اثرانگشت پردازش نشد. لطفاً دوباره امتحان کنید."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"حسگر اثر انگشت کثیف است. لطفاً آن را تمیز کنید و دوباره امتحان نمایید."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"این دستگاه حسگر اثر انگشت ندارد."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"حسگر بهطور موقت غیرفعال است."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"انگشت <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"استفاده از اثر انگشت"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"استفاده از اثر انگشت یا قفل صفحه"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"برای ادامه، از اثر انگشتتان استفاده کنید"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"«بازگشایی با چهره» در این دستگاه پشتیبانی نمیشود."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"حسگر بهطور موقت غیرفعال است."</string> <string name="face_name_template" msgid="3877037340223318119">"چهره <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"استفاده از «بازگشایی با چهره»"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"استفاده از قفل صفحه یا چهره"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"برای ادامه، از «بازگشایی با چهره» استفاده کنید"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"نماد چهره"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"اخبار و مجله"</string> <string name="app_category_maps" msgid="6395725487922533156">"نقشه و پیمایش"</string> <string name="app_category_productivity" msgid="1844422703029557883">"بهرهوری"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"دسترسپذیری"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"فضای ذخیرهسازی دستگاه"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"اشکالزدایی USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ساعت"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index be0cd2358b8b..2e0d6cddc3d4 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Antaa sovelluksen muokata kuvakokoelmaasi."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lukea mediakokoelmasi sijainteja"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Antaa sovelluksen lukea mediakokoelmasi sijainteja."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Käytä biometriikkaa"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Käytä biometriikkaa tai näytön lukitusta"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Vahvista henkilöllisyytesi"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Jatka käyttämällä biometriikkaa"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrinen laitteisto ei käytettävissä"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Todennus peruutettu"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Ei tunnistettu"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Todennus peruutettu"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-koodia, kuviota tai salasanaa ei ole asetettu"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Virhe todennuksessa"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Käytä näytön lukitusta"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Jatka lisäämällä laitteesi kirjautumistiedot"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Sormenjälki havaittiin vain osittain. Yritä uudelleen."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Sormenjäljen prosessointi epäonnistui. Yritä uudelleen."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Sormenjälkitunnistin on likainen. Puhdista tunnistin ja yritä uudelleen."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Laitteessa ei ole sormenjälkitunnistinta."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tunnistin poistettu väliaikaisesti käytöstä."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Sormi <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Käytä sormenjälkeä"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Käytä sormenjälkeä tai näytön lukitusta"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Jatka sormenjäljen avulla"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Tämä laite ei tue Face Unlockia."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Tunnistin poistettu väliaikaisesti käytöstä."</string> <string name="face_name_template" msgid="3877037340223318119">"Kasvot <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Käytä Face Unlockia"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Käytä Face Unlockia tai näytön lukitusta"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Jatka käyttämällä Face Unlockia"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Kasvokuvake"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Uutiset ja lehdet"</string> <string name="app_category_maps" msgid="6395725487922533156">"Kartat ja navigointi"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Tuottavuus"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Esteettömyys"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Laitteen tallennustila"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-vianetsintä"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"tunnit"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 5c26e683d354..1ebc60465f47 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Autorise l\'application à modifier votre collection de photos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lire les positions issues de votre collection multimédia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Autorise l\'application à lire les positions indiquées dans votre collection multimédia."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utiliser les données biométriques"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utiliser les données biométriques ou le verrouillage de l\'écran"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmez que c\'est vous"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilisez votre méthode d\'authentification biométrique pour continuer"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Matériel biométrique indisponible"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentification annulée"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Données biométriques non reconnues"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Authentification annulée"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Aucun NIP, schéma ou mot de passe défini"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Erreur d\'authentification"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Utiliser le verrouillage de l\'écran"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Entrez votre authentifiant d\'appareil pour continuer"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Empreinte digitale partielle détectée. Veuillez réessayer."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Impossible de reconnaître l\'empreinte digitale. Veuillez réessayer."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Le capteur d\'empreintes digitales est sale. Veuillez le nettoyer et réessayer."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Cet appareil ne possède pas de capteur d\'empreintes digitales."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Le capteur a été désactivé temporairement."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utiliser l\'empreinte digitale"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utiliser l\'empreinte digitale ou le verrouillage de l\'écran"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilisez votre empreinte digitale pour continuer"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Cet appar. ne prend pas en charge le déverr. par reconn. faciale."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Le capteur a été désactivé temporairement."</string> <string name="face_name_template" msgid="3877037340223318119">"Visage <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Utiliser le déverrouillage par reconnaissance faciale"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Utiliser la reconnaissance faciale ou le verrouillage de l\'écran"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Utilisez le déverrouillage par reconnaissance faciale pour continuer"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Icône visage"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Actualités et magazines"</string> <string name="app_category_maps" msgid="6395725487922533156">"Cartes et navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productivité"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accessibilité"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Mémoire de l\'appareil"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Débogage USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"heures"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 3d8856df65bf..ce36dbc9ba21 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Autorise l\'application à modifier votre bibliothèque photo."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"consulter des positions issues de votre bibliothèque multimédia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Autorise l\'application à consulter des positions issues de votre bibliothèque multimédia."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utiliser la biométrie"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utiliser la biométrie ou le verrouillage de l\'écran"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmez votre identité"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilisez la biométrie pour continuer"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Matériel biométrique indisponible"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentification annulée"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Non reconnu"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Authentification annulée"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Aucun code, schéma ni mot de passe n\'est défini"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Erreur d\'authentification"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Utiliser verrouillage écran"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Saisissez l\'identifiant de l\'appareil pour continuer"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Empreinte digitale partiellement détectée. Veuillez réessayer."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Impossible de reconnaître l\'empreinte digitale. Veuillez réessayer."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Le lecteur d\'empreinte digitale est sale. Veuillez le nettoyer, puis réessayer."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aucun lecteur d\'empreinte digitale n\'est installé sur cet appareil."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Capteur temporairement désactivé."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utiliser l\'empreinte digitale"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utiliser votre empreinte digitale ou le verrouillage de l\'écran"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilisez votre empreinte digitale pour continuer"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock n\'est pas compatible avec cet appareil."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Capteur temporairement désactivé."</string> <string name="face_name_template" msgid="3877037340223318119">"Visage <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Utiliser Face Unlock"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Utiliser Face Lock ou le verrouillage de l\'écran"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Utilisez Face Unlock pour continuer"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Icône visage"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Actualités et magazines"</string> <string name="app_category_maps" msgid="6395725487922533156">"Plans et navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productivité"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accessibilité"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Mémoire de l\'appareil"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Débogage USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"heures"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 1c5ab13035f3..9d95af8badc2 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que a aplicación modifique a túa colección de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ler localizacións da túa colección multimedia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que a aplicación lea as localizacións da túa colección multimedia."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utilizar desbloqueo biométrico"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utilizar desbloqueo biométrico ou credencial do dispositivo"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que es ti"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Para continuar, utiliza o desbloqueo biométrico"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"O hardware biométrico non está dispoñible"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Cancelouse a autenticación"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Non se recoñeceu"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Cancelouse a autenticación"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Non se estableceu ningún PIN, padrón ou contrasinal"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Produciuse un erro ao realizar a autenticación"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar credencial do dispositivo"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Para continuar, mete a credencial do dispositivo"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Detectouse unha impresión dixital parcial. Téntao de novo."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Non se puido procesar a impresión dixital. Téntao de novo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"O sensor de impresión dixital está sucio. Límpao e téntao de novo."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo non ten sensor de impresión dixital."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Desactivouse o sensor temporalmente."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilizar impresión dixital"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilizar impresión dixital ou credencial do dispositivo"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utiliza a túa impresión dixital para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Este dispositivo non admite o desbloqueo facial."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Desactivouse o sensor temporalmente."</string> <string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Utilizar desbloqueo facial"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Utilizar desbloqueo facial ou credencial do dispositivo"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Para continuar, utiliza o desbloqueo facial"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Icona cara"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Noticias e revistas"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mapas e navegación"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produtividade"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accesibilidade"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Almacenamento do dispositivo"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuración por USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index fd3a06baa3fa..334ba2d8b532 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"એપને તમારો ફોટો સંગ્રહ સંશોધિત કરવાની મંજૂરી આપે છે."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"આપના મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવા"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"એપને તમારા મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવાની મંજૂરી આપે છે."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"બાયોમેટ્રિક્સનો ઉપયોગ કરો"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"બાયોમેટ્રિક્સ અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"તે તમે જ છો એ ચકાસો"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"આગળ વધવા માટે બાયોમેટ્રિકનો ઉપયોગ કરો"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"બાયોમેટ્રિક હાર્ડવેર ઉપલબ્ધ નથી"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"પ્રમાણીકરણ રદ કર્યું"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"ઓળખાયેલ નથી"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"પ્રમાણીકરણ રદ કર્યું"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"કોઈ પિન, પૅટર્ન અથવા પાસવર્ડ સેટ કરેલો નથી"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"પ્રમાણિત કરવામાં ભૂલ આવી"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"સ્ક્રીન લૉકનો ઉપયોગ કરો"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"ચાલુ રાખવા માટે તમારા ડિવાઇસની લૉગ ઇન વિગત દાખલ કરો"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"આંશિક ફિંગરપ્રિન્ટ મળી. કૃપા કરીને ફરી પ્રયાસ કરો."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ફિંગરપ્રિન્ટ પ્રક્રિયા કરી શકાઈ નથી. કૃપા કરીને ફરી પ્રયાસ કરો."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ફિંગરપ્રિન્ટ સેન્સર ગંદું છે. કૃપા કરીને સાફ કરો અને ફરી પ્રયાસ કરો."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"આ ડિવાઇસમાં કોઈ ફિંગરપ્રિન્ટ સેન્સર નથી."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"સેન્સર હંગામી રૂપે બંધ કર્યું છે."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"આંગળી <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ફિંગરપ્રિન્ટ અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ચાલુ રાખવા માટે તમારી ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"આ ડિવાઇસ પર ફેસ અનલૉક કરવાની સુવિધા નથી."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"સેન્સર હંગામી રૂપે બંધ કર્યું છે."</string> <string name="face_name_template" msgid="3877037340223318119">"ચહેરાનું <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"ફેસ અનલૉકનો ઉપયોગ કરો"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ફેસ લૉક અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"આગળ વધવા માટે ફેસ અનલૉકનો ઉપયોગ કરો"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"ચહેરા આઇકન"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"સમાચાર અને સામાયિકો"</string> <string name="app_category_maps" msgid="6395725487922533156">"Maps અને નેવિગેશન"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ઉત્પાદકતા"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"ઍક્સેસિબિલિટી"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ડિવાઇસ સ્ટૉરેજ"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ડિબગિંગ"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"કલાક"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index be64e904b908..16e848f83d6d 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"इससे ऐप्लिकेशन को आपके फ़ोटो संग्रह में बदलाव करने की मंज़ूरी दी जाती है."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"अपने मीडिया संग्रह से जगह की जानकारी ऐक्सेस करने की अनुमति दें"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"इससे ऐप्लिकेशन को आपके मीडिया संग्रह से जगह की जानकारी ऐक्सेस करने की अनुमति दी जाती है."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"बायोमेट्रिक्स इस्तेमाल करें"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"बायोमेट्रिक्स या स्क्रीन लॉक का क्रेडेंशियल इस्तेमाल करें"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"अपनी पहचान की पुष्टि करें"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"जारी रखने के लिए, बायोमेट्रिक्स इस्तेमाल करें"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेयर उपलब्ध नहीं है"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"प्रमाणीकरण रद्द किया गया"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"पहचान नहीं हो पाई"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"प्रमाणीकरण रद्द किया गया"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"पिन, पैटर्न या पासवर्ड सेट नहीं है"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"गड़बड़ी की पुष्टि की जा रही है"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"स्क्रीन लॉक का क्रेडेंशियल इस्तेमाल करें"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"जारी रखने के लिए, अपने डिवाइस का क्रेडेंशियल डालें"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"अधूरा फ़िंगरप्रिंट प्रोसेस हो सका. कृपया फिर से कोशिश करें."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"फ़िंगरप्रिंट प्रोसेस नहीं हो सका. कृपया दोबारा कोशिश करें."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"फ़िंगरप्रिंट सेंसर गंदा है. कृपया साफ़ करें और फिर कोशिश करें."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"फ़िंगरप्रिंट <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"फ़िंगरप्रिंट इस्तेमाल करें"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"फ़िंगरप्रिंट या स्क्रीन लॉक का क्रेडेंशियल इस्तेमाल करें"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"जारी रखने के लिए फ़िंगरप्रिंट का इस्तेमाल करें"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"इस डिवाइस पर \'मालिक का चेहरा पहचानकर अनलॉक\' काम नहीं करती है."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string> <string name="face_name_template" msgid="3877037340223318119">"चेहरा <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"\'फ़ेस अनलॉक\' इस्तेमाल करें"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"चेहरा पहचानने की सुविधा या स्क्रीन लॉक का क्रेडेंशियल इस्तेमाल करें"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"जारी रखने के लिए, \'फ़ेस अनलॉक\' इस्तेमाल करें"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"चेहरे का आइकॉन"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"समाचार और पत्रिकाएं"</string> <string name="app_category_maps" msgid="6395725487922533156">"Maps और नेविगेशन ऐप्लिकेशन"</string> <string name="app_category_productivity" msgid="1844422703029557883">"उत्पादकता"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"सुलभता"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"डिवाइस में जगह"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB डीबग करना"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"घंटा"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 3a6ce2179c96..15c36c9ba604 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -553,23 +553,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Omogućuje aplikaciji izmjenu vaše zbirke fotografija."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"čitanje lokacija iz vaše medijske zbirke"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Omogućuje aplikaciji čitanje lokacija iz vaše medijske zbirke."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Upotreba biometrije"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Upotreba biometrijske autentifikacije ili zaključavanja zaslona"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite da ste to vi"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Upotrijebite svoju biometrijsku autentifikaciju da biste nastavili"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikacija otkazana"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Nije prepoznato"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikacija otkazana"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nisu postavljeni PIN, uzorak ni zaporka"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Pogreška prilikom autentifikacije"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Upotreba zaključavanja zaslona"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Unesite vjerodajnicu uređaja da biste nastavili"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Otkriven je djelomični otisak prsta. Pokušajte ponovo."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Obrada otiska prsta nije uspjela. Pokušajte ponovo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzor otiska prsta nije čist. Očistite ga i pokušajte ponovo."</string> @@ -592,10 +587,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor otiska prsta."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Upotreba otiska prsta"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Upotreba otiska prsta ili zaključavanja zaslona"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Nastavite pomoću otiska prsta"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -641,12 +634,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string> <string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Upotreba otključavanja licem"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Upotreba lica ili zaključavanja zaslona"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Upotrijebite otključavanje licem da biste nastavili"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string> @@ -1998,8 +1988,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Vijesti i časopisi"</string> <string name="app_category_maps" msgid="6395725487922533156">"Karte i navigacija"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktivnost"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Pristupačnost"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Pohrana na uređaju"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Otklanjanje pogrešaka putem USB-a"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"sat"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 3cd0aba28c04..f28f1b66518f 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Engedélyezi az alkalmazásnak a fényképgyűjtemény módosítását."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"helyek olvasása a médiagyűjteményből"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Engedélyezi az alkalmazásnak a helyek médiagyűjteményből való olvasását."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometriai feloldás használata"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"A folytatás biometriai feloldással vagy képernyőzárral lehetséges"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Igazolja, hogy Ön az"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"A folytatás biometriai feloldással lehetséges"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrikus hardver nem áll rendelkezésre"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Hitelesítés megszakítva"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Nem ismerhető fel"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Hitelesítés megszakítva"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nem állított be PIN-kódot, mintát vagy jelszót."</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Hiba történt a hitelesítés közben"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Képernyőzár használata"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"A folytatáshoz adja meg az eszköz hitelesítési adatait"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"A rendszer az ujjlenyomatnak csak egy részletét érzékelte. Próbálkozzon újra."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nem sikerült feldolgozni az ujjlenyomatot. Próbálkozzon újra."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Az ujjlenyomat-olvasó koszos. Tisztítsa meg, majd próbálkozzon újra."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ez az eszköz nem rendelkezik ujjlenyomat-érzékelővel."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Az érzékelő átmenetileg le van tiltva."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. ujj"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Ujjlenyomat használata"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"A folytatás ujjlenyomattal vagy képernyőzárral lehetséges"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"A folytatáshoz használja ujjlenyomatát"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Az eszköz nem támogatja az arcalapú feloldást"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Az érzékelő átmenetileg le van tiltva."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> arc"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Arcalapú feloldás használata"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"A folytatás arcalapú feloldással vagy képernyőzárral lehetséges"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"A folytatás arcalapú feloldással lehetséges"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Arcikon"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Hírlapok és folyóiratok"</string> <string name="app_category_maps" msgid="6395725487922533156">"Térképek és navigáció"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Irodai alkalmazások"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Kisegítő alkalmazások"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Eszköztárhely"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-hibakeresés"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"óra"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 8d6e42e1e7ff..959cb572333e 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Թույլ է տալիս հավելվածին փոփոխել ձեր լուսանկարների հավաքածուն:"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ճանաչել տեղադրության մասին տվյալները մեդիա բովանդակության հավաքածուից"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Թույլ է տալիս հավելվածին ճանաչել տեղադրության մասին տվյալները ձեր մեդիա բովանդակության հավաքածուից:"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Կենսաչափական համակարգեր"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Օգտագործել կենսաչափական համակարգեր կամ էկրանի կողպում"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Հաստատեք ձեր ինքնությունը"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Շարունակելու համար օգտագործեք կենսաչափական համակարգեր"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Կենսաչափական սարքը հասանելի չէ"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Նույնականացումը չեղարկվեց"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Չհաջողվեց ճանաչել"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Նույնականացումը չեղարկվեց"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ավելացրեք PIN կոդ, նախշ կամ գաղտնաբառ։"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Չհաջողվեց նույնականացնել"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Էկրանի կողպում"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Շարունակելու համար մուտքագրեք սարքի նույնականացման տվյալները"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Մատնահետքն ամբողջությամբ չի սկանավորվել: Փորձեք նորից:"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Չհաջողվեց մշակել մատնահետքը: Նորից փորձեք:"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Մատնահետքերի սենսորն աղտոտված է: Մաքրեք այն և փորձեք նորից:"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Այս սարքը չունի մատնահետքերի սկաներ։"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Տվիչը ժամանակավորապես անջատված է:"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Մատնահետք <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Օգտագործել մատնահետք"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Օգտագործել մատնահետք կամ էկրանի կողպում"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Շարունակելու համար անհրաժեշտ է ձեր մատնահետքը"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Դեմքով ապակողպումն այս սարքում չի աջակցվում"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Տվիչը ժամանակավորապես անջատված է:"</string> <string name="face_name_template" msgid="3877037340223318119">"Դեմք <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Օգտագործել դեմքով ապակողպում"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Օգտագործել դեմքով ապակողպում կամ էկրանի կողպում"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Շարունակելու համար օգտագործեք դեմքով ապակողպում"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Դեմքի պատկերակ"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Նորություններ և ամսագրեր"</string> <string name="app_category_maps" msgid="6395725487922533156">"Քարտեզներ և նավարկում"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Արդյունավետություն"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Հատուկ գործառույթներ"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Սարքի հիշողություն"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-ով վրիպազերծում"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ժամ"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 28d2ed8963b0..9f692098f12a 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Mengizinkan aplikasi untuk memodifikasi koleksi foto Anda."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"membaca lokasi dari koleksi media Anda"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Mengizinkan aplikasi untuk membaca lokasi dari koleksi media Anda."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Gunakan biometrik"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gunakan biometrik atau kunci layar"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifikasi bahwa ini memang Anda"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Gunakan biometrik untuk melanjutkan"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrik tidak tersedia"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentikasi dibatalkan"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Tidak dikenali"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentikasi dibatalkan"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Tidak ada PIN, pola, atau sandi yang disetel"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Error saat mengautentikasi"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Gunakan kunci layar"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Masukkan kredensial perangkat untuk melanjutkan"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Sebagian sidik jari terdeteksi. Coba lagi."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Tidak dapat memproses sidik jari. Coba lagi."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Sensor sidik jari kotor. Bersihkan dan coba lagi."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Perangkat ini tidak memiliki sensor sidik jari."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor dinonaktifkan untuk sementara."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gunakan sidik jari"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gunakan sidik jari atau kunci layar"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gunakan sidik jari untuk melanjutkan"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock tidak didukung di perangkat ini."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor dinonaktifkan untuk sementara."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> wajah"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Gunakan face unlock"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gunakan face lock atau kunci layar"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Gunakan face unlock untuk melanjutkan"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ikon wajah"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Berita & Majalah"</string> <string name="app_category_maps" msgid="6395725487922533156">"Peta & Navigasi"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktivitas"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Aksesibilitas"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Penyimpanan perangkat"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Proses debug USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"jam"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index cd5b35affb86..0e11f033b033 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Leyfir forritinu að breyta myndasafninu þínu."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lesa staðsetningar úr efnissafninu þínu"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Leyfir forritinu að lesa staðsetningar úr efnissafninu þínu."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Nota lífkenni"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Nota lífkenni eða skjálás"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Staðfestu hver þú ert"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Notaðu lífkenni til að halda áfram"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Lífkennavélbúnaður ekki tiltækur"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Hætt við auðkenningu"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Þekktist ekki"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Hætt við auðkenningu"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ekkert PIN-númer, mynstur eða aðgangsorð stillt"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Villa við auðkenningu"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Nota skjálás"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Færðu inn skilríki tækisins til að halda áfram"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Hluti fingrafars greindist. Reyndu aftur."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Ekki var hægt að vinna úr fingrafarinu. Reyndu aftur."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingrafaraskynjarinn er óhreinn. Hreinsaðu hann og reyndu aftur."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Þetta tæki er ekki með fingrafaralesara."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Slökkt tímabundið á skynjara."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Fingur <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Nota fingrafar"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Nota fingrafar eða skjálás"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Notaðu fingrafarið þitt til að halda áfram"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Andlitsopnun er ekki studd í þessu tæki."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Slökkt tímabundið á skynjara."</string> <string name="face_name_template" msgid="3877037340223318119">"Andlit <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Nota andlitsopnun"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Nota andlit eða skjálás"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Notaðu andlitsopnun til að halda áfram"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Andlitstákn"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Fréttir og tímarit"</string> <string name="app_category_maps" msgid="6395725487922533156">"Kort og leiðsögn"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Aðstoð"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Aðgengi"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Geymslurými tækis"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-villuleit"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"klst."</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 83b4a684ae58..b41996e4cb58 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Consente all\'app di modificare la tua raccolta di foto."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lettura delle posizioni dalla tua raccolta multimediale"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Consente all\'app di leggere le posizioni dalla tua raccolta multimediale."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usa la biometria"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usa la biometria o il blocco schermo"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica la tua identità"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Usa la biometria per continuare"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrico non disponibile"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticazione annullata"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Non riconosciuto"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticazione annullata"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Non hai impostato PIN, sequenza o password"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Errore durante l\'autenticazione"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usa il blocco schermo"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Inserisci la credenziale del dispositivo per continuare"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Rilevata impronta parziale. Riprova."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Impossibile elaborare l\'impronta. Riprova."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Il sensore di impronte è sporco. Puliscilo e riprova."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Questo dispositivo non dispone di sensore di impronte."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensore temporaneamente disattivato."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dito <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usa l\'impronta"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usa l\'impronta o il blocco schermo"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilizza la tua impronta per continuare"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Sblocco con il volto non supportato su questo dispositivo."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensore temporaneamente disattivato."</string> <string name="face_name_template" msgid="3877037340223318119">"Volto <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Usa Sblocco con il volto"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usa Sblocco con il volto o il blocco schermo"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Usa Sblocco con il volto per continuare"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Icona volto"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Notizie e riviste"</string> <string name="app_category_maps" msgid="6395725487922533156">"Maps e Navigatore"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produttività"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accessibilità"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Memoria dispositivo"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Debug USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ora"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index e3cb913fe0fd..be05cc00c3b0 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -556,23 +556,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"מאפשרת לאפליקציה לשנות את אוסף התמונות שלך."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"לקרוא מיקומים מאוסף המדיה שלך"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"מאפשרת לאפליקציה לקרוא מיקומים מאוסף המדיה שלך."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"שימוש במידע ביומטרי"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"שימוש במידע ביומטרי בנעילת מסך"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"אימות זהותך"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"יש להשתמש במידע ביומטרי כדי להמשיך"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"חומרה ביומטרית לא זמינה"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"האימות בוטל"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"לא זוהתה"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"האימות בוטל"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"עוד לא הוגדרו קוד גישה, קו ביטול נעילה או סיסמה"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"שגיאה באימות"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"שימוש בנעילת מסך"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"יש להזין את פרטי הכניסה של המכשיר כדי להמשיך"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"זוהתה טביעת אצבע חלקית. אפשר לנסות שוב."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"לא ניתן היה לעבד את טביעת האצבע. נסה שוב."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"החיישן של טביעות האצבעות מלוכלך. צריך לנקות אותו ולנסות שוב."</string> @@ -595,10 +590,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"במכשיר זה אין חיישן טביעות אצבע."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"החיישן מושבת באופן זמני."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"אצבע <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"שימוש בטביעת אצבע"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"שימוש בטביעת אצבע או בנעילת מסך"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"יש להשתמש בטביעת האצבע כדי להמשיך"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -644,12 +637,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"המכשיר הזה לא תומך בשחרור נעילה על ידי זיהוי פנים."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"החיישן מושבת באופן זמני."</string> <string name="face_name_template" msgid="3877037340223318119">"פנים <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"שחרור נעילה על ידי זיהוי פנים"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"שימוש בזיהוי פנים או בנעילת מסך"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"יש להשתמש בשחרור נעילה על ידי זיהוי פנים כדי להמשיך"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"סמל הפנים"</string> @@ -2030,8 +2020,7 @@ <string name="app_category_news" msgid="1172762719574964544">"חדשות וכתבי עת"</string> <string name="app_category_maps" msgid="6395725487922533156">"מפות וניווט"</string> <string name="app_category_productivity" msgid="1844422703029557883">"פרודוקטיביות"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"נגישות"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"שטח האחסון במכשיר"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"ניקוי באגים ב-USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"שעה"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 4b54bdbc2469..e7c343872b95 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"写真コレクションの変更をアプリに許可します。"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"メディア コレクションの位置情報の読み取り"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"メディア コレクションの位置情報の読み取りをアプリに許可します。"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"生体認証の使用"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"生体認証または画面ロックの使用"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"本人確認"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"続行するには生体認証を使用してください"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"生体認証ハードウェアが利用できません"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"認証をキャンセルしました"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"認識されませんでした"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"認証をキャンセルしました"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN、パターン、パスワードが設定されていません"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"エラー認証"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"画面ロックの使用"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"続行するにはデバイスの認証情報を入力してください"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"指紋を一部しか検出できませんでした。もう一度お試しください。"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"指紋を処理できませんでした。もう一度お試しください。"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"指紋認証センサーに汚れがあります。汚れを落としてもう一度お試しください。"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"このデバイスには指紋認証センサーがありません。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"センサーが一時的に無効になっています。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"指紋 <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"指紋の使用"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"指紋または画面ロックの使用"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"続行するには指紋認証を使用してください"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"このデバイスでは、顔認証はご利用いただけません。"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"センサーが一時的に無効になっています。"</string> <string name="face_name_template" msgid="3877037340223318119">"顔 <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"顔認証の使用"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"顔認証または画面ロックの使用"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"続行するには顔認証を使用してください"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"顔アイコン"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"ニュース&雑誌"</string> <string name="app_category_maps" msgid="6395725487922533156">"地図&ナビ"</string> <string name="app_category_productivity" msgid="1844422703029557883">"仕事効率化"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"ユーザー補助"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"デバイスのストレージ"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB デバッグ"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"時"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 7a03bb32efcb..3fb6c6954a98 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"აპი შეძლებს თქვენი ფოტოკოლექციის შეცვლას."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"მდებარეობების გაცნობა თქვენი მედიაკოლექციიდან"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"აპი შეძლებს მდებარეობების გაცნობას თქვენი მედიაკოლექციიდან."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"გამოიყენეთ ბიომეტრიული სისტემა"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"გამოიყენეთ ბიომეტრიული სისტემა ან ეკრანის დაბლოკვა"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"დაადასტურეთ ვინაობა"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"გასაგრძელებლად გამოიყენეთ თქვენი ბიომეტრიული მონაცემები"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ბიომეტრიული აპარატურა მიუწვდომელია"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"ავტორიზაცია გაუქმდა"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"არ არის ამოცნობილი"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"ავტორიზაცია გაუქმდა"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-კოდი, ნიმუში ან პაროლი დაყენებული არ არის"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"შეცდომა ავთენტიკაციისას"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"გამოიყენეთ ეკრანის დაბლოკვა"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"გასაგრძელებლად შეიყვანეთ თქვენი მოწყობილობის ავტორიზაციის მონაცემი"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"აღმოჩენილია თითის ნაწილობრივი ანაბეჭდი. გთხოვთ, სცადოთ ხელახლა."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"თითის ანაბეჭდის დამუშავება ვერ მოხერხდა. გთხოვთ, ცადოთ ხელახლა."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"თითის ანაბეჭდის სენსორი დაბინძურებულია. გთხოვთ, გაასუფთაოთ და სცადოთ ხელახლა."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ამ მოწყობილობას არ აქვს თითის ანაბეჭდის სენსორი."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"სენსორი დროებით გათიშულია."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"თითი <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"გამოიყენეთ თითის ანაბეჭდი"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"გამოიყენეთ თითის ანაბეჭდი ან ეკრანის დაბლოკვა"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"გასაგრძელებლად გამოიყენეთ თქვენი თითის ანაბეჭდი"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"განბლოკვა სახით ამ მოწყობილობაზე მხარდაჭერილი არ არის."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"სენსორი დროებით გათიშულია."</string> <string name="face_name_template" msgid="3877037340223318119">"სახე <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"გამოიყენეთ სახით განბლოკვა"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"გამოიყენეთ სახე ან ეკრანის დაბლოკვა"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"გასაგრძელებლად გამოიყენეთ სახით განბლოკვა"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"სახის ხატულა"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"ახალი ამბები და ჟურნალები"</string> <string name="app_category_maps" msgid="6395725487922533156">"რუკები და ნავიგაცია"</string> <string name="app_category_productivity" msgid="1844422703029557883">"პროდუქტიულობა"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"მარტივი წვდომა"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"მოწყობილობის მეხსიერება"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB გამართვა"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"საათი"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 1c00fe65ba82..4404603f09fc 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Қолданбаға суреттер жинағын өзгертуге мүмкіндік береді."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"медиамазмұн жинағынан геодеректерді оқу"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Қолданбаға медиамазмұн жинағынан геодеректерді оқуға мүмкіндік береді."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Биометриканы пайдалану"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Биометриканы немесе экран құлпын пайдалану"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Бұл сіз екеніңізді растаңыз"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Жалғастыру үшін биометрикаңызды пайдаланыңыз."</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалық жабдық жоқ"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аутентификациядан бас тартылды."</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Танылмады"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Аутентификациядан бас тартылды."</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ешқандай PIN коды, өрнек немесе құпия сөз орнатылмаған."</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Аутентификациялауда қате шықты."</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Экран құлпын пайдалану"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Жалғастыру үшін құрылғының тіркелу деректерін енгізіңіз."</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Саусақ ізі толық анықталмады. Әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Саусақ ізін өңдеу мүмкін емес. Әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Сканер лас. Тазалап, әрекетті қайталаңыз."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бұл құрылғыда саусақ ізін оқу сканері жоқ."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик уақытша өшірулі."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> саусағы"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Саусақ ізін пайдалану"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Саусақ ізін немесе экран құлпын пайдалану"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Жалғастыру үшін саусақ ізін пайдаланыңыз."</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Бұл құрылғыда Face Unlock функциясы істемейді."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик уақытша өшірулі."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> беті"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Face Unlock функциясын пайдалану"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Face Lock функциясын немесе экран құлпын пайдалану"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Жалғастыру үшін Face Unlock функциясын пайдаланыңыз."</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Бет белгішесі"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Газеттер және журналдар"</string> <string name="app_category_maps" msgid="6395725487922533156">"Карта және навигация"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Өнімділік"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Арнайы мүмкіндіктер"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Құрылғы жады"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB арқылы түзету"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"сағат"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index a2512d2a9d08..fb1155318137 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"អនុញ្ញាតឱ្យកម្មវិធីកែប្រែបណ្ដុំរូបថតរបស់អ្នក។"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"អានទីតាំងពីបណ្ដុំមេឌៀរបស់អ្នក"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"អនុញ្ញាតឱ្យកម្មវិធីអានទីតាំងពីបណ្ដុំមេឌៀរបស់អ្នក។"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"ប្រើជីវមាត្រ"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ប្រើជីវមាត្រ ឬការចាក់សោអេក្រង់"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ផ្ទៀងផ្ទាត់ថាជាអ្នក"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ប្រើជីវមាត្ររបស់អ្នក ដើម្បីបន្ត"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"មិនអាចប្រើឧបករណ៍ស្កេនស្នាមម្រាមដៃបានទេ"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"បានបោះបង់ការផ្ទៀងផ្ទាត់"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"មិនអាចសម្គាល់បានទេ"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"បានបោះបង់ការផ្ទៀងផ្ទាត់"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"គ្មានការកំណត់កូដ pin លំនាំ ឬពាក្យសម្ងាត់ទេ"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"មានបញ្ហាក្នុងការផ្ទៀងផ្ទាត់"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ប្រើការចាក់សោអេក្រង់"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"បញ្ចូលព័ត៌មានផ្ទៀងផ្ទាត់ឧបករណ៍របស់អ្នក ដើម្បីបន្ត"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"បានផ្តិតយកស្នាមម្រាមដៃមិនពេញលក្ខណៈ។ សូមព្យាយាមម្តងទៀត។"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"មិនអាចដំណើរការស្នាមម្រាមដៃបានទេ។ សូមព្យាយាមម្តងទៀត។"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ឧបករណ៍ចាប់ស្នាមម្រាមដៃគឺប្រឡាក់។ សូមសម្អាត រួចព្យាយាមម្តងទៀត។"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ឧបករណ៍នេះមិនមានឧបករណ៍ចាប់ស្នាមម្រាមដៃទេ។"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"បានបិទឧបករណ៍ចាប់សញ្ញាជាបណ្តោះអាសន្ន។"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ម្រាមដៃ <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ប្រើស្នាមម្រាមដៃ"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ប្រើស្នាមម្រាមដៃ ឬការចាក់សោអេក្រង់"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ប្រើស្នាមម្រាមដៃរបស់អ្នក ដើម្បីបន្ត"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"មិនអាចប្រើការដោះសោតាមទម្រង់មុខនៅលើឧបករណ៍នេះបានទេ។"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"បានបិទឧបករណ៍ចាប់សញ្ញាជាបណ្តោះអាសន្ន។"</string> <string name="face_name_template" msgid="3877037340223318119">"ផ្ទៃមុខទី <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"ប្រើការដោះសោតាមទម្រង់មុខ"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ប្រើមុខ ឬការចាក់សោអេក្រង់"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"ប្រើការដោះសោតាមទម្រង់មុខ ដើម្បីបន្ត"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"រូបផ្ទៃមុខ"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"ព័ត៌មាន និងទស្សនាវដ្ដី"</string> <string name="app_category_maps" msgid="6395725487922533156">"ផែនទី និងការរុករក"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ផលិតភាព"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"ភាពងាយស្រួល"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ទំហំផ្ទុកឧបករណ៍"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"ការកែកំហុសតាម USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ម៉ោង"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index e9110c217d4a..f484344d7891 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"ನಿಮ್ಮ ಫೋಟೋ ಸಂಗ್ರಹಣೆಯನ್ನು ಮಾರ್ಪಡಿಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಿ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"ಬಯೋಮೆಟ್ರಿಕ್ಸ್ ಬಳಸಿ"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ಬಯೋಮೆಟ್ರಿಕ್ಸ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ಇದು ನೀವೇ ಎಂದು ಪರಿಶೀಲಿಸಿ"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಬಯೋಮೆಟ್ರಿಕ್ ಬಳಸಿ"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ಬಯೋಮೆಟ್ರಿಕ್ ಹಾರ್ಡ್ವೇರ್ ಲಭ್ಯವಿಲ್ಲ"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"ಪ್ರಮಾಣೀಕರಣವನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"ಪ್ರಮಾಣೀಕರಣವನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ಪಿನ್, ಪ್ಯಾಟರ್ನ್ ಅಥವಾ ಪಾಸ್ವರ್ಡ್ ಸೆಟ್ ಮಾಡಿಲ್ಲ"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"ದೃಢೀಕರಿಸುವಾಗ ದೋಷ ಎದುರಾಗಿದೆ"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಬಳಸಿ"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಸಾಧನದ ರುಜುವಾತನ್ನು ನಮೂದಿಸಿ"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ಭಾಗಶಃ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಪತ್ತೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಕೊಳೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಅದನ್ನು ಸ್ವಚ್ಛಗೊಳಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ಈ ಸಾಧನವು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಹೊಂದಿಲ್ಲ."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ಸೆನ್ಸಾರ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ಫಿಂಗರ್ <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಬಳಸಿ"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಬಳಸಿ"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಬಳಸಿ"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"ಈ ಸಾಧನದಲ್ಲಿ ಫೇಸ್ ಅನ್ಲಾಕ್ ವೈಶಿಷ್ಟ್ಯವು ಬೆಂಬಲಿತವಾಗಿಲ್ಲ."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"ಸೆನ್ಸಾರ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string> <string name="face_name_template" msgid="3877037340223318119">"ಮುಖದ <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ಫೇಸ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"ಮುಂದುವರಿಸಲು ಫೇಸ್ ಅನ್ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"ಮುಖದ ಐಕಾನ್"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"ಸುದ್ದಿ ಮತ್ತು ನಿಯತಕಾಲಿಕೆಗಳು"</string> <string name="app_category_maps" msgid="6395725487922533156">"Maps ಮತ್ತು ನ್ಯಾವಿಗೇಶನ್"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ಉತ್ಪಾದಕತೆ"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"ಪ್ರವೇಶಿಸುವಿಕೆ"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ಸಾಧನ ಸಂಗ್ರಹಣೆ"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ಡೀಬಗ್ ಮಾಡುವಿಕೆ"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ಗಂಟೆ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 16e2efa6f5c0..78cc1b572e04 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"앱에서 사진 컬렉션을 수정하도록 허용합니다."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"미디어 컬렉션에서 위치 읽기"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"앱에서 미디어 컬렉션의 위치를 읽도록 허용합니다."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"생체 인식 사용"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"생체 인식 또는 화면 잠금을 사용"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"본인 확인"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"생체 인식을 사용하여 계속하세요"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"생체 인식 하드웨어를 사용할 수 없음"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"인증이 취소되었습니다."</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"인식할 수 없음"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"인증이 취소되었습니다."</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN, 패턴, 비밀번호가 설정되지 않음"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"인증 오류"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"화면 잠금 사용"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"계속하려면 기기의 사용자 인증 정보를 입력하세요"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"지문이 일부만 인식되었습니다. 다시 시도해 주세요."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"지문을 인식할 수 없습니다. 다시 시도해 주세요."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"지문 센서를 깨끗이 닦고 다시 시도하세요."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"기기에 지문 센서가 없습니다."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"센서가 일시적으로 사용 중지되었습니다."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"손가락 <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"지문 사용"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"지문 또는 화면 잠금 사용"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"계속하려면 지문을 사용하세요."</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"이 기기에서는 얼굴인식 잠금해제가 지원되지 않습니다."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"센서가 일시적으로 사용 중지되었습니다."</string> <string name="face_name_template" msgid="3877037340223318119">"얼굴 <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"얼굴인식 잠금해제 사용"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"얼굴 또는 화면 잠금 사용"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"얼굴인식 잠금해제를 사용하여 계속하세요"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"얼굴 아이콘"</string> @@ -1699,7 +1689,7 @@ <string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"기능 간에 전환하려면 세 손가락을 사용하여 위로 스와이프한 다음 잠시 기다립니다."</string> <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"확대"</string> <string name="user_switched" msgid="7249833311585228097">"현재 사용자는 <xliff:g id="NAME">%1$s</xliff:g>님입니다."</string> - <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>(으)로 전환하는 중…"</string> + <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>로 전환하는 중…"</string> <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>님을 로그아웃하는 중…"</string> <string name="owner_name" msgid="8713560351570795743">"소유자"</string> <string name="error_message_title" msgid="4082495589294631966">"오류"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"뉴스/잡지"</string> <string name="app_category_maps" msgid="6395725487922533156">"지도/내비게이션"</string> <string name="app_category_productivity" msgid="1844422703029557883">"생산성"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"접근성"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"기기 저장용량"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB 디버깅"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"시"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 258422574dd7..5d8b8980d2f5 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Колдонмого сүрөт жыйнагыңызды өзгөртүүгө мүмкүнчүлүк берет."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"медиа жыйнагыңыз сакталган жерлерди окуу"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Колдонмого медиа жыйнагыңыз сакталган жерлерди окууга мүмкүнчүлүк берет."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Биометрикалык жөндөөлөрдү колдонуу"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Биометрикалык жөндөөнү же экрандын кулпусун колдонуу"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Өзүңүздү ырастаңыз"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Улантуу үчүн биометрикалык жөндөөнү колдонуу"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалык аппарат жеткиликсиз"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аныктыгын текшерүү жокко чыгарылды"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Таанылган жок"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Аныктыгын текшерүү жокко чыгарылды"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN код, графикалык ачкыч же сырсөз коюлган жок"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Аутентификация катасы"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Экран кулпусун колдонуу"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Улантуу үчүн түзмөгүңүздүн эсептик дайындарын киргизиңиз"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Манжа изи жарым-жартылай аныкталды. Кайталап көрүңүз."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Манжа изи иштелбей койду. Кайталап көрүңүз."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Манжа изинин сенсору кирдеп калган. Тазалап, кайталап көрүңүз."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бул түзмөктө манжа изинин сенсору жок."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сенсор убактылуу өчүрүлгөн."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>-манжа"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Манжа изин колдонуу"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Манжа изин же экрандын кулпусун колдонуу"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Улантуу үчүн манжаңыздын изин колдонуңуз"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Жүзүнөн таануу функциясы бул түзмөктө иштебейт."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Сенсор убактылуу өчүрүлгөн."</string> <string name="face_name_template" msgid="3877037340223318119">"Жүз <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Жүзүнөн таанып ачууну колдонуу"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Жүзүнөн таанып ачууну же экрандын кулпусун колдонуу"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Улантуу үчүн жүзүнөн таанып ачууну колдонуу"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Жүздүн сүрөтчөсү"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Жаңылыктар жана журналдар"</string> <string name="app_category_maps" msgid="6395725487922533156">"Карталар жана чабыттоо"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Өндүрүш категориясы"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Атайын мүмкүнчүлүктөр"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Түзмөктүн сактагычы"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB аркылуу мүчүлүштүктөрдү аныктоо"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"саат"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 7fb32e7d2034..fcf47edbfc47 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"ອະນຸຍາດໃຫ້ແອັບແກ້ໄຂຄໍເລັກຊັນຮູບຂອງທ່ານ."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ອ່ານສະຖານທີ່ຈາກຄໍເລັກຊັນມີເດຍຂອງທ່ານ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"ອະນຸຍາດໃຫ້ແອັບອ່ານສະຖານທີ່ຈາກຄໍເລັກຊັນມີເດຍຂອງທ່ານ."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"ໃຊ້ລະບົບຊີວະມິຕິ"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ໃຊ້ລະບົບຊີວະມິຕິ ຫຼື ການລັອກໜ້າຈໍ"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ຢັ້ງຢືນວ່າແມ່ນທ່ານ"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ໃຊ້ລະບົບຊີວະມິຕິຂອງທ່ານເພື່ອດຳເນີນການຕໍ່"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ຮາດແວຊີວະມິຕິບໍ່ສາມາດໃຊ້ໄດ້"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"ຍົກເລີກການຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"ບໍ່ຮັບຮູ້"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"ຍົກເລີກການຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ບໍ່ໄດ້ຕັ້ງ PIN, ຮູບແບບປົດລັອກ ຫຼື ລະຫັດຜ່ານ"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"ເກີດຄວາມຜິດພາດໃນການພິສູດຢືນຢັນ"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ໃຊ້ການລັອກໜ້າຈໍ"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"ລະບຸຂໍ້ມູນການເຂົ້າສູ່ລະບົບອຸປະກອນຂອງທ່ານເພື່ອດຳເນີນການຕໍ່"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ກວດພົບລາຍນີ້ວມືບາງສ່ວນແລ້ວ. ກະລຸນາລອງໃໝ່ອີກ."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ບໍ່ສາມາດດຳເນີນການລາຍນີ້ວມືໄດ້. ກະລຸນາລອງໃໝ່ອີກ."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ເຊັນເຊີລາຍນີ້ວມືເປື້ອນ. ກະລຸນາທຳຄວາມສະອາດ ແລະລອງໃໝ່ອີກ."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ອຸປະກອນນີ້ບໍ່ມີເຊັນເຊີລາຍນິ້ວມື."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ປິດການເຮັດວຽກຂອງເຊັນເຊີໄວ້ຊົ່ວຄາວແລ້ວ."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ນີ້ວມື <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ໃຊ້ລາຍນິ້ວມື"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ໃຊ້ລາຍນິ້ວມື ຫຼື ການລັອກໜ້າຈໍ"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ໃຊ້ລາຍນີ້ວມືຂອງທ່ານເພື່ອສືບຕໍ່"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"ບໍ່ຮອງຮັບການປົດລັອກດ້ວຍໜ້າຢູ່ອຸປະກອນນີ້."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"ປິດການເຮັດວຽກຂອງເຊັນເຊີໄວ້ຊົ່ວຄາວແລ້ວ."</string> <string name="face_name_template" msgid="3877037340223318119">"ໃບໜ້າ <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"ໃຊ້ການປົດລັອກດ້ວຍໜ້າ"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ໃຊ້ໃບໜ້າ ຫຼື ການລັອກໜ້າຈໍ"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"ໃຊ້ການປົດລັອກດ້ວຍໜ້າເພື່ອດຳເນີນການຕໍ່"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"ໄອຄອນໃບໜ້າ"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"News & Magazines"</string> <string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ຜະລິດຕະພາບ"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"ການຊ່ວຍເຂົ້າເຖິງ"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ບ່ອນຈັດເກັບຂໍ້ມູນອຸປະກອນ"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"ການດີບັກຜ່ານ USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ຊົ່ວໂມງ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 820d7a029b9e..4afef3be17d4 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -556,23 +556,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Programai leidžiama keisti nuotraukų kolekciją."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"skaityti vietoves iš medijos kolekcijos"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Programai leidžiama skaityti vietoves iš medijos kolekcijos."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Naudoti biometrinius duomenis"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Naudoti biometrinius duomenis arba ekrano užraktą"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Patvirtinkite, kad tai jūs"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Norėdami tęsti, naudokite biometrinius duomenis"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrinė aparatinė įranga nepasiekiama"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikavimas atšauktas"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Neatpažinta"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikavimas atšauktas"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenustatytas PIN kodas, atrakinimo piešinys arba slaptažodis"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Autentifikuojant įvyko klaida"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Naudoti ekrano užraktą"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Jei norite tęsti, įveskite įrenginio prisijungimo duomenis"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Aptiktas dalinis piršto antspaudas. Bandykite dar kartą."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nepavyko apdoroti piršto antspaudo. Bandykite dar kartą."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Piršto antspaudo jutiklis purvinas. Nuvalykite ir bandykite dar kartą."</string> @@ -595,10 +590,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šiame įrenginyje nėra kontrolinio kodo jutiklio."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Jutiklis laikinai išjungtas."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> pirštas"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Naudoti kontrolinį kodą"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Naudoti kontrolinį kodą arba ekrano užraktą"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Naudokite kontrolinį kodą, kad galėtumėte tęsti"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -644,12 +637,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Atrakinimas pagal veidą šiame įrenginyje nepalaikomas."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Jutiklis laikinai išjungtas."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> veidas"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Naudoti atrakinimą pagal veidą"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Naudoti atrakinimą pagal veidą arba ekrano užraktą"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Norėdami tęsti, naudokite atrakinimą pagal veidą"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Veido pkt."</string> @@ -2030,8 +2020,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Naujienos ir žurnalai"</string> <string name="app_category_maps" msgid="6395725487922533156">"Žemėlapiai ir navigacija"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktyvumas"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Pritaikomumas"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Įrenginio saugykla"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB derinimas"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"valanda"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 91c38a4ac3bd..8fbfb279daf9 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -553,23 +553,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Ļauj lietotnei pārveidot jūsu fotoattēlu kolekciju."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"Lasīt atrašanās vietas no jūsu multivides kolekcijas"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Ļauj lietotnei lasīt atrašanās vietas no jūsu multivides kolekcijas."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometrijas izmantošana"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrijas vai ekrāna bloķēšanas izmantošana"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Apstipriniet, ka tas esat jūs"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Lai turpinātu, izmantojiet biometriju"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisko datu aparatūra nav pieejama"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikācija ir atcelta"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Dati nav atpazīti"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikācija ir atcelta"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN, kombinācija vai parole nav iestatīta"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Autentifikācijas kļūda"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ekrāna bloķēšanas metodes izmantošana"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Lai turpinātu, ievadiet savas ierīces akreditācijas datus"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Noteikts daļējs pirksta nospiedums. Lūdzu, mēģiniet vēlreiz."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nevarēja apstrādāt pirksta nospiedumu. Lūdzu, mēģiniet vēlreiz."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Pirkstu nospiedumu sensors ir netīrs. Lūdzu, notīriet to un mēģiniet vēlreiz."</string> @@ -592,10 +587,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šajā ierīcē nav pirksta nospieduma sensora."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensors ir īslaicīgi atspējots."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. pirksts"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Pirksta nospieduma izmantošana"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Pirksta nospieduma vai ekrāna bloķēšanas metodes izmantošana"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Lai turpinātu, izmantojiet pirksta nospiedumu"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -641,12 +634,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Autorizācija pēc sejas šajā ierīcē netiek atbalstīta"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensors ir īslaicīgi atspējots."</string> <string name="face_name_template" msgid="3877037340223318119">"Seja <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Autorizācija pēc sejas"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Autorizācijas pēc sejas vai ekrāna bloķēšanas metodes izmantošana"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Lai turpinātu, izmantojiet autorizāciju pēc sejas"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Sejas ikona"</string> @@ -1998,8 +1988,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Ziņas un žurnāli"</string> <string name="app_category_maps" msgid="6395725487922533156">"Kartes un navigācija"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktivitāte"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Pieejamība"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Ierīces krātuve"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB atkļūdošana"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"stunda"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 88fb8246845f..9d07234910fe 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -20,7 +20,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="byteShort" msgid="202579285008794431">"Б"</string> + <string name="byteShort" msgid="202579285008794431">"B"</string> <string name="kilobyteShort" msgid="2214285521564195803">"KB"</string> <string name="megabyteShort" msgid="6649361267635823443">"MB"</string> <string name="gigabyteShort" msgid="7515809460261287991">"GB"</string> @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Дозволува апликацијата да ја менува вашата збирка на фотографии."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"да чита локации од вашата збирка на аудиовизуелни содржини"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Дозволува апликацијата да чита локации од вашата збирка на аудиовизуелни содржини."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Користи биометрика"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Користи биометрика или заклучен екран"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Потврдете дека сте вие"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Користете ја вашата биометрика за да продолжите"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрискиот хардвер е недостапен"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Проверката е откажана"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Непознат"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Проверката е откажана"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Не е поставен PIN, шема или лозинка"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Грешка при проверката"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Користи заклучување екран"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Внесете го акредитивот на уредот за да продолжите"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Откриен е делумен отпечаток. Обидете се повторно."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Отпечатокот не може да се обработи. Обидете се повторно."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Сензорот за отпечатоци е валкан. Исчистете го и обидете се повторно."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Уредов нема сензор за отпечатоци."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорот е привремено оневозможен."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Користи отпечаток"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Користи отпечаток или заклучување екран"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Користете го отпечатокот за да продолжите"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"„Отклучувањето со лик“ не е поддржано на уредов."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Сензорот е привремено оневозможен."</string> <string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Користи отклучување со лик"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Користи лик или заклучување екран"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Користете отклучување со лик за да продолжите"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Икона"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Вести и списанија"</string> <string name="app_category_maps" msgid="6395725487922533156">"Карти и навигација"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Продуктивност"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Пристапност"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Простор на уредот"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Отстранување грешки на USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"час"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index f82267d115eb..8d91c5182b16 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"നിങ്ങളുടെ ഫോട്ടോ ശേഖരം പരിഷ്ക്കരിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുക"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"ബയോമെട്രിക്സ് ഉപയോഗിക്കുക"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ബയോമെട്രിക്സ് അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ഇത് നിങ്ങളാണെന്ന് പരിശോധിച്ചുറപ്പിക്കുക"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"തുടരാൻ ബയോമെട്രിക് ഉപയോഗിക്കുക"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ബയോമെട്രിക് ഹാർഡ്വെയർ ലഭ്യമല്ല"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കി"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"തിരിച്ചറിഞ്ഞില്ല"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കി"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"പിന്നോ പാറ്റേണോ പാസ്വേഡോ സജ്ജീകരിച്ചിട്ടില്ല"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"പിശക് പരിശോധിച്ചുറപ്പിക്കുന്നു"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"തുടരാൻ നിങ്ങളുടെ ഉപകരണ ക്രെഡൻഷ്യലുകൾ നൽകുക"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ഫിംഗർപ്രിന്റ് ഭാഗികമായി തിരിച്ചറിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ഫിംഗർപ്രിന്റ് പ്രോസസ് ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ഫിംഗർപ്രിന്റ് സെൻസറിൽ ചെളിയുണ്ട്. അത് വൃത്തിയാക്കി വീണ്ടും ശ്രമിക്കുക."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ഈ ഉപകരണത്തിൽ ഫിംഗർപ്രിന്റ് സെൻസറില്ല."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"സെൻസർ താൽക്കാലികമായി പ്രവർത്തനരഹിതമാക്കി."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"കൈവിരൽ <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ഫിംഗർപ്രിന്റ് അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"തുടരുന്നതിന് നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"മുഖം തിരിച്ചറിഞ്ഞുള്ള അൺലോക്ക് ഈ ഉപകരണം പിന്തുണയ്ക്കുന്നില്ല."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"സെൻസർ താൽക്കാലികമായി പ്രവർത്തനരഹിതമാക്കി."</string> <string name="face_name_template" msgid="3877037340223318119">"മുഖം <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"മുഖം തിരിച്ചറിഞ്ഞുള്ള അൺലോക്ക് ഉപയോഗിക്കുക"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"മുഖം അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"തുടരാൻ മുഖം തിരിച്ചറിഞ്ഞുള്ള അൺലോക്ക് ഉപയോഗിക്കുക"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"മുഖത്തിന്റെ ഐക്കൺ"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"വാർത്തകളും മാസികകളും"</string> <string name="app_category_maps" msgid="6395725487922533156">"മാപ്പുകളും നാവിഗേഷനും"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ഉല്പ്പാദനക്ഷമത"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"ഉപയോഗസഹായി"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ഉപകരണ സ്റ്റോറേജ്"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ഡീബഗ്ഗിംഗ്"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"മണി."</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 203ad3d39060..faec2be635ba 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Таны зургийн цуглуулгыг тохируулах зөвшөөрлийг аппад олгодог."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"медиа цуглуулгаасаа байршлыг унших"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Таны медиа цуглуулгаас байршлыг унших зөвшөөрлийг аппад олгодог."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Биометр ашиглах"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Биометр эсвэл дэлгэцийн түгжээ ашиглах"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Өөрийгөө мөн гэдгийг баталгаажуулаарай"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Үргэлжлүүлэхийн тулд биометрээ ашиглана уу"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрийн техник хангамж боломжгүй байна"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Нотолгоог цуцаллаа"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Таниагүй"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Нотолгоог цуцаллаа"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Тохируулсан пин, хээ эсвэл нууц үг алга"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Баталгаажуулахад алдаа гарлаа"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Дэлгэцийн түгжээг ашиглах"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Үргэлжлүүлэхийн тулд төхөөрөмжийнхөө мандат үнэмлэхийг оруулна уу"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Хурууны хээг дутуу уншуулсан байна. Дахин оролдоно уу."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Хурууны хээ боловсруулж чадахгүй байна. Дахин оролдоно уу."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Хурууны хээ мэдрэгч бохирдсон байна. Цэвэрлэсний дараа дахин оролдоно уу."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Энэ төхөөрөмжид хурууны хээ мэдрэгч алга."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Хурууны хээ <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Хурууны хээ ашиглах"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Хурууны хээ эсвэл дэлгэцийн түгжээ ашиглах"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Үргэлжлүүлэхийн тулд хурууны хээгээ ашиглаарай"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Царайгаар тайлахыг энэ төхөөрөмж дээр дэмждэггүй."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string> <string name="face_name_template" msgid="3877037340223318119">"Царай <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Царайгаар тайлахыг ашиглах"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Царай эсвэл дэлгэцийн түгжээ ашиглах"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Үргэлжлүүлэхийн тулд царайгаар тайлахыг ашиглана уу"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Царайны дүрс тэмдэг"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Мэдээ & сэтгүүл"</string> <string name="app_category_maps" msgid="6395725487922533156">"Газрын зураг & зүг чиг"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Бүтээмж"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Хандалт"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Төхөөрөмжийн сан"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB дебаг хийлт"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"Цаг"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index d8d43a64ab7b..3bf30638d95a 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Membenarkan apl mengubah suai koleksi foto anda."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"baca lokasi daripada koleksi media anda"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Membenarkan apl membaca lokasi daripada koleksi media anda."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Gunakan biometrik"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gunakan biometrik atau kunci skrin"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Sahkan itu anda"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Gunakan biometrik anda untuk meneruskan"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Perkakasan biometrik tidak tersedia"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Pengesahan dibatalkan"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Tidak dikenali"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Pengesahan dibatalkan"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pin, corak atau kata laluan tidak ditetapkan"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Ralat semasa membuat pengesahan"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Gunakan kunci skrin"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Masukkan bukti kelayakan peranti anda untuk meneruskan"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Cap jari separa dikesan. Sila cuba lagi."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Tidak dapat memproses cap jari. Sila cuba lagi."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Penderia cap jari kotor. Sila bersihkan dan cuba lagi."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Peranti ini tiada penderia cap jari."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Penderia dilumpuhkan sementara."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gunakan cap jari"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gunakan cap jari atau kunci skrin"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gunakan cap jari anda untuk teruskan"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Wajah buka kunci tidak disokong pada peranti ini."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Penderia dilumpuhkan sementara."</string> <string name="face_name_template" msgid="3877037340223318119">"Wajah <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Gunakan wajah buka kunci"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gunakan kunci wajah atau skrin"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Gunakan wajah buka kunci untuk meneruskan"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ikon wajah"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Berita & Majalah"</string> <string name="app_category_maps" msgid="6395725487922533156">"Peta & Navigasi"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktiviti"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Kebolehaksesan"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Storan peranti"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Penyahpepijatan USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"jam"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 82008b069346..f301483c6b56 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"အက်ပ်အား သင့်ဓာတ်ပုံစုစည်းမှုကို ပြုပြင်ခွင့်ပေးသည်။"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"သင့်မီဒီယာစုစည်းမှုမှ တည်နေရာများကို ဖတ်ခြင်း"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"အက်ပ်အား သင့်မီဒီယာစုစည်းမှုမှ တည်နေရာများကို ဖတ်ခွင့်ပေးသည်။"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"ဇီဝမက်ထရစ်အချက်အလက်များ သုံးခြင်း"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ဇီဝမက်ထရစ်အချက်အလက်များ (သို့) ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"သင်ဖြစ်ကြောင်း အတည်ပြုပါ"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ရှေ့ဆက်ရန် သင်၏ ဇီဝမက်ထရစ်အချက်အလက်ကို သုံးပါ"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ဇီဝအချက်အလက်သုံး ကွန်ပျူတာစက်ပစ္စည်း မရရှိနိုင်ပါ"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်လိုက်သည်"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"မသိ"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်လိုက်သည်"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ပင်နံပါတ်၊ လော့ခ်ပုံစံ သို့မဟုတ် စကားဝှက် သတ်မှတ်မထားပါ"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"အထောက်အထားစိစစ်ရာတွင် အမှားအယွင်းရှိနေသည်"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"ရှေ့ဆက်ရန် သင့်စက်ပစ္စည်း၏ အထောက်အထားကို ထည့်သွင်းပါ"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"လက်ဗွေ တစ်ပိုင်းတစ်စ တွေ့ရှိသည်။ ကျေးဇူးပြု၍ ထပ်စမ်းကြည့်ပါ။"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"လက်ဗွေယူ၍ မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"လက်ဗွေဖတ်ကိရိယာ ညစ်ပေနေသည်။ ကျေးဇူးပြု၍ သန့်ရှင်းလိုက်ပြီး ပြန်စမ်းကြည့်ပါ။"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ဤစက်တွင် လက်ဗွေအာရုံခံကိရိယာ မရှိပါ။"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"လက်ချောင်း <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"လက်ဗွေ သုံးခြင်း"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"လက်ဗွေ (သို့) ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ရှေ့ဆက်ရန် သင့်လက်ဗွေကို သုံးပါ"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"ဤစက်ပစ္စည်းတွင် မျက်နှာမှတ် သော့ဖွင့်ခြင်းကို သုံး၍မရပါ။"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string> <string name="face_name_template" msgid="3877037340223318119">"မျက်နှာ <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"မျက်နှာမှတ်သော့ဖွင့်ခြင်းကို သုံးခြင်း"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"မျက်နှာမှတ်သော့ဖွင့်ခြင်း (သို့) ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"ရှေ့ဆက်ရန် မျက်နှာမှတ်သော့ဖွင့်ခြင်းကို သုံးပါ"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"မျက်နှာသင်္ကေတ"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"သတင်းနှင့် မဂ္ဂဇင်းများ"</string> <string name="app_category_maps" msgid="6395725487922533156">"မြေပုံနှင့် ခရီးလမ်းညွှန်ချက်"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ထုတ်လုပ်နိုင်မှု"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"အများသုံးစွဲနိုင်မှု"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"စက်ပစ္စည်း သိုလှောင်ခန်း"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB အမှားရှာပြင်ခြင်း"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"နာရီ"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 1bafd6006e3c..07cf9c06f8fe 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Lar appen gjøre endringer i bildesamlingen din."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lese posisjoner fra mediesamlingen din"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Lar appen lese posisjoner fra mediesamlingen din."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Bruk biometri"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Bruk biometri eller skjermlås"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Bekreft at det er deg"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Bruk biometri for å fortsette"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk maskinvare er utilgjengelig"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentiseringen er avbrutt"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Ikke gjenkjent"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentiseringen er avbrutt"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-kode, mønster eller passord er ikke angitt"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Feil under autentiseringen"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Bruk skjermlås"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Skriv inn enhetslegitimasjonen din for å fortsette"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Deler av fingeravtrykket er registrert. Prøv på nytt."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Kunne ikke registrere fingeravtrykket. Prøv på nytt."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingeravtrykksensoren er skitten. Rengjør den og prøv på nytt."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enheten har ikke fingeravtrykkssensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidig slått av."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Bruk fingeravtrykk"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Bruk fingeravtrykk eller skjermlås"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Bruk fingeravtrykket ditt for å fortsette"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansiktslås støttes ikke på denne enheten"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensoren er midlertidig slått av."</string> <string name="face_name_template" msgid="3877037340223318119">"Ansikt <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Bruk ansiktslås"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Bruk ansikts- eller skjermlås"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Bruk ansiktslås for å fortsette"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ansiktikon"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Nyheter og tidsskrifter"</string> <string name="app_category_maps" msgid="6395725487922533156">"Kart og navigering"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktivitet"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Tilgjengelighet"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Lagring på enheten"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-feilsøking"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"time"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index a15a9a46a4d1..6295d4455ac2 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"यसले एपलाई तपाईंको तस्बिरको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"आफ्नो मिडियाको सङ्ग्रहका स्थानहरू पढ्नुहोस्"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"यसले एपलाई तपाईंको मिडिया सङ्ग्रहका स्थानहरू पढ्न दिन्छ।"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"बायोमेट्रिक्स प्रयोग गर्नुहोस्"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"बायोमेट्रिक्स वा स्क्रिन लक प्रयोग गर्नुहोस्"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"यो व्यक्ति तपाईं नै हो भन्ने प्रमाणित गर्नुहोस्"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"जारी राख्न आफ्नो बायोमेट्रिक प्रयोग गर्नुहोस्"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेयर उपलब्ध छैन"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"प्रमाणीकरण रद्द गरियो"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"पहिचान भएन"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"प्रमाणीकरण रद्द गरियो"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"कुनै पनि PIN, ढाँचा वा पासवर्ड सेट गरिएको छैन"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"प्रमाणित गर्ने क्रममा त्रुटि भयो"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"स्क्रिन लक प्रयोग गर्नुहोस्"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"जारी राख्न आफ्नो यन्त्रको PIN, प्याटर्न वा पासवर्ड हाल्नुहोस्"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"आंशिक फिंगरप्रिन्ट पत्ता लाग्यो। कृपया फेरि प्रयास गर्नुहोस्।"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"फिंगरप्रिन्ट प्रशोधन गर्न सकिएन। कृपया फेरि प्रयास गर्नुहोस्।"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"फिंगरप्रिन्ट सेन्सर फोहोर छ। कृपया सफा गरेर फेरि प्रयास गर्नुहोस्।"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"यो यन्त्रमा कुनै पनि फिंगरप्रिन्ट सेन्सर छैन।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"केही समयका लागि सेन्सर असक्षम पारियो।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"औंला <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"फिंगरप्रिन्ट वा स्क्रिन लक प्रयोग गर्नुहोस्"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"जारी राख्न आफ्नो फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"यस यन्त्रमा फेस अनलक सुविधा प्रयोग गर्न मिल्दैन।"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"केही समयका लागि सेन्सर असक्षम पारियो।"</string> <string name="face_name_template" msgid="3877037340223318119">"अनुहार <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"फेस अनलक प्रयोग गर्नुहोस्"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"फेस अनलक वा स्क्रिन लक प्रयोग गर्नुहोस्"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"जारी राख्न फेस अनलक प्रयोग गर्नुहोस्"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"अनुहारको आइकन"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"समाचार तथा पत्रिकाहरू"</string> <string name="app_category_maps" msgid="6395725487922533156">"नक्सा तथा नेभिगेसन"</string> <string name="app_category_productivity" msgid="1844422703029557883">"उत्पादकत्व"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"सर्वसुलभता"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"यन्त्रको भण्डारण"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB डिबग प्रक्रिया"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"घन्टा"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 1f2680e2b101..46880ea78016 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Hiermee sta je de app toe je fotocollectie aan te passen."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"locaties van je mediacollecties bekijken"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Hiermee sta je de app toe locaties van je mediacollectie te bekijken."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometrische gegevens gebruiken"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrische gegevens of schermvergrendeling gebruiken"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Je identiteit verifiëren"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Gebruik je biometrische gegevens om door te gaan"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrische hardware niet beschikbaar"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Verificatie geannuleerd"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Niet herkend"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Verificatie geannuleerd"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Geen pincode, patroon of wachtwoord ingesteld"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Fout bij verificatie"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Schermvergrendeling gebruiken"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Geef de inloggegevens van je apparaat op om door te gaan"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Gedeeltelijke vingerafdruk gedetecteerd. Probeer het opnieuw."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Kan vingerafdruk niet verwerken. Probeer het opnieuw."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"De vingerafdruksensor moet worden schoongemaakt. Probeer het daarna opnieuw."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dit apparaat heeft geen vingerafdruksensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor tijdelijk uitgeschakeld."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Vingerafdruk gebruiken"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Vingerafdruk of schermvergrendeling gebruiken"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gebruik je vingerafdruk om door te gaan."</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ontgrendelen via gezichtsherkenning wordt niet ondersteund op dit apparaat."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor tijdelijk uitgeschakeld."</string> <string name="face_name_template" msgid="3877037340223318119">"Gezicht <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Ontgrendelen via gezichtsherkenning gebruiken"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gezicht of schermgrendeling gebruiken"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Gebruik ontgrendelen via gezichtsherkenning om door te gaan"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Gezichtspictogram"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Nieuws en tijdschriften"</string> <string name="app_category_maps" msgid="6395725487922533156">"Maps en navigatie"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productiviteit"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Toegankelijkheid"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Apparaatopslag"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-foutopsporing"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"uur"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index e3c3c09214c8..7d65cde300bd 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"ଆପଣଙ୍କ ଫଟୋ ସଂଗ୍ରହ ପରିବର୍ତ୍ତନ କରିବାକୁ ଆପ୍ ଅନୁମତି ଦେଇଥାଏ।"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ଆପଣଙ୍କ ମିଡିଆ ସଂଗ୍ରହ ଠାରୁ ଲୋକେସନ୍ଗୁଡିକୁ ପଢନ୍ତୁ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"ଆପଣଙ୍କ ମିଡିଆ ସଂଗ୍ରହ ଠାରୁ ଅବସ୍ଥାନଗୁଡିକୁ ପଢିବାକୁ ଆପ୍ ଅନୁମତି ଦେଇଥାଏ।"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"ବାୟୋମେଟ୍ରିକ୍ସ ବ୍ୟବହାର କରନ୍ତୁ"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ବାୟୋମେଟ୍ରିକ୍ସ ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ଏହା ଆପଣ ବୋଲି ଯାଞ୍ଚ କରନ୍ତୁ"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ବାୟୋମେଟ୍ରିକ୍ସ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ବାୟୋମେଟ୍ରିକ୍ ହାର୍ଡୱେର୍ ଉପଲବ୍ଧ ନାହିଁ"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"ପ୍ରାମାଣିକତାକୁ ବାତିଲ୍ କରାଯାଇଛି"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"ପ୍ରାମାଣିକତାକୁ ବାତିଲ୍ କରାଯାଇଛି"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"କୌଣସି ପିନ୍, ପେଟେର୍ନ ବା ପାସ୍ୱର୍ଡ ସେଟ୍ ନାହିଁ"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"ପ୍ରାମାଣିକରଣ କରିବା ସମୟରେ ତ୍ରୁଟି"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଡିଭାଇସର କ୍ରେଡେନ୍ସିଆଲ୍ ଲେଖନ୍ତୁ"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ଆଂଶିକ ଟିପଚିହ୍ନ ଚିହ୍ନଟ ହେଲା। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ଟିପଚିହ୍ନ ପ୍ରୋସେସ୍ କରାଯାଇପାରିଲା ନାହିଁ। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ଟିପଚିହ୍ନ ସେନ୍ସର୍ ମଇଳା ହୋଇଯାଇଛି। ଦୟାକରି ସଫା କରନ୍ତୁ ଓ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ଏହି ଡିଭାଇସ୍ରେ ଟିପଚିହ୍ନ ସେନ୍ସର୍ ନାହିଁ।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ସେନ୍ସରକୁ ଅସ୍ଥାୟୀ ଭାବେ ଅକ୍ଷମ କରାଯାଇଛି।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ଆଙ୍ଗୁଠି <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ଟିପଚିହ୍ନ ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"ଏହି ଡିଭାଇସ୍ରେ ଫେସ୍ ଅନ୍ଲକ୍ ସମର୍ଥିତ ନୁହେଁ।"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"ସେନ୍ସରକୁ ଅସ୍ଥାୟୀ ଭାବେ ଅକ୍ଷମ କରାଯାଇଛି।"</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g>ଙ୍କ ଫେସ୍"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"ଫେସ୍ ଅନଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ଫେସ୍ ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"ଜାରି ରଖିବାକୁ ଫେସ୍ ଅନଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"ଫେସ୍ ଆଇକନ୍"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"ଖବର ଓ ମ୍ୟାଗାଜିନ୍"</string> <string name="app_category_maps" msgid="6395725487922533156">"ମାନଚିତ୍ର ଓ ନେଭିଗେଶନ୍"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ଉତ୍ପାଦକତା"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"ଆକ୍ସେସିବିଲିଟୀ"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ଡିଭାଇସ୍ ଷ୍ଟୋରେଜ୍"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ଡିବଗିଂ"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ଘଣ୍ଟା"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 01bf27679dc2..4b183205b14c 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -556,23 +556,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Zezwala aplikacji na modyfikowanie kolekcji zdjęć."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"odczytywanie lokalizacji z kolekcji multimediów"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Zezwala aplikacji na odczytywanie lokalizacji z kolekcji multimediów."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Używaj biometrii"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Używaj biometrii lub blokady ekranu"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potwierdź swoją tożsamość"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Użyj biometrii, by kontynuować"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Sprzęt biometryczny niedostępny"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Anulowano uwierzytelnianie"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Nie rozpoznano"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Anulowano uwierzytelnianie"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nie ustawiono kodu PIN, wzoru ani hasła"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Podczas uwierzytelniania wystąpił błąd"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Używaj blokady ekranu"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Podaj dane logowania do urządzenia, aby kontynuować"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Odcisk palca został odczytany tylko częściowo. Spróbuj ponownie."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nie udało się przetworzyć odcisku palca. Spróbuj ponownie."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Czytnik linii papilarnych jest zabrudzony. Wyczyść go i spróbuj ponownie."</string> @@ -595,10 +590,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"To urządzenie nie jest wyposażone w czytnik linii papilarnych."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Czujnik jest tymczasowo wyłączony."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Odcisk palca <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Używaj odcisku palca"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Używaj odcisku palca lub blokady ekranu"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Użyj odcisku palca, by kontynuować"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -644,12 +637,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"To urządzenie nie obsługuje rozpoznawania twarzy."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Czujnik jest tymczasowo wyłączony."</string> <string name="face_name_template" msgid="3877037340223318119">"Twarz <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Używaj rozpoznawania twarzy"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Używaj rozpoznawania twarzy lub blokady ekranu"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Użyj rozpoznawania twarzy, aby kontynuować"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona twarzy"</string> @@ -2030,8 +2020,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Wiadomości i czasopisma"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mapy i nawigacja"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktywność"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Ułatwienia dostępu"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Pamięć urządzenia"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Debugowanie USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"godz."</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index aa693582f0fa..7d028f91b23f 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que o app modifique sua coleção de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ler locais na sua coleção de mídias"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que o app leia os locais na sua coleção de mídias."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usar biometria"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar biometria ou bloqueio de tela"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme que é você"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use seus dados biométricos para continuar"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Não reconhecido"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticação cancelada"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenhum PIN, padrão ou senha configurado"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Erro na autenticação"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar bloqueio de tela"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Insira as credenciais do dispositivo para continuar"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Impressão digital parcial detectada. Tente novamente."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Não foi possível processar a impressão digital. Tente novamente."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"O sensor de impressão digital está sujo. Limpe-o e tente novamente."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar impressão digital"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar impressão digital ou bloqueio de tela"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use sua impressão digital para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"O desbloqueio facial não é compatível com este dispositivo."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor desativado temporariamente."</string> <string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Usar desbloqueio facial"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usar reconhecimento facial ou bloqueio de tela"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Use o desbloqueio facial para continuar"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ícone facial"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Notícias e revistas"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mapas e navegação"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produtividade"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Acessibilidade"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Armazenamento do dispositivo"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuração USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 232a17219eb4..a01db5e3fca6 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que a app modifique a sua coleção de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ler as localizações a partir da sua coleção de multimédia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que a app leia as localizações a partir da sua coleção de multimédia."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utilizar a biometria"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utilizar a biometria ou o bloqueio de ecrã"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme a sua identidade"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilize a biometria para continuar."</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível."</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Não reconhecido."</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticação cancelada"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenhum PIN, padrão ou palavra-passe definidos."</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Erro ao autenticar."</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Utilizar o bloqueio de ecrã"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Introduza a credencial do dispositivo para continuar."</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Impressão digital parcial detetada. Tente novamente."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Não foi possível processar a impressão digital. Tente novamente."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"O sensor de impressões digitais está sujo. Limpe-o e tente novamente."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem sensor de impressões digitais."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporariamente desativado."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilizar a impressão digital"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilizar o bloqueio de ecrã ou a impressão digital"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilize a sua impressão digital para continuar."</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Desbloqueio facial não suportado neste dispositivo."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporariamente desativado."</string> <string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Utilizar o desbloqueio facial"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Utilizar o bloqueio através do rosto ou de ecrã"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Utilize o desbloqueio facial para continuar."</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ícone de rosto"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Notícias e revistas"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mapas e navegação"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produtividade"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Acessibilidade"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Armazenamento do dispositivo"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuração USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index aa693582f0fa..7d028f91b23f 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que o app modifique sua coleção de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ler locais na sua coleção de mídias"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que o app leia os locais na sua coleção de mídias."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usar biometria"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar biometria ou bloqueio de tela"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme que é você"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use seus dados biométricos para continuar"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Não reconhecido"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticação cancelada"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenhum PIN, padrão ou senha configurado"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Erro na autenticação"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar bloqueio de tela"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Insira as credenciais do dispositivo para continuar"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Impressão digital parcial detectada. Tente novamente."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Não foi possível processar a impressão digital. Tente novamente."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"O sensor de impressão digital está sujo. Limpe-o e tente novamente."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar impressão digital"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar impressão digital ou bloqueio de tela"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use sua impressão digital para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"O desbloqueio facial não é compatível com este dispositivo."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor desativado temporariamente."</string> <string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Usar desbloqueio facial"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usar reconhecimento facial ou bloqueio de tela"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Use o desbloqueio facial para continuar"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ícone facial"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Notícias e revistas"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mapas e navegação"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produtividade"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Acessibilidade"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Armazenamento do dispositivo"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuração USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 01daa557ca99..e8c553908c29 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -553,23 +553,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite aplicației să vă modifice colecția de fotografii."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"citiți locațiile din colecția media"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite aplicației să citească locațiile din colecția dvs. media."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Folosiți sistemele biometrice"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Folosiți sistemele biometrice sau blocarea ecranului"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmați-vă identitatea"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Folosiți sistemele biometrice pentru a continua"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometric indisponibil"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentificarea a fost anulată"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Nu este recunoscut"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentificarea a fost anulată"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nu este setat niciun cod PIN, model sau parolă"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Eroare la autentificare"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Folosiți blocarea ecranului"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Introduceți datele de conectare ale dispozitivului pentru a continua"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"S-a detectat parțial amprenta. Încercați din nou."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Amprenta nu a putut fi procesată. Încercați din nou."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzorul pentru amprente este murdar. Curățați-l și încercați din nou."</string> @@ -592,10 +587,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dispozitivul nu are senzor de amprentă."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzorul este dezactivat temporar."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Degetul <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Folosiți amprenta"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Folosiți amprenta sau blocarea ecranului"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Folosiți amprenta pentru a continua"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -641,12 +634,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Deblocarea facială nu este acceptată pe dispozitiv."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzorul este dezactivat temporar."</string> <string name="face_name_template" msgid="3877037340223318119">"Chip <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Folosiți deblocarea facială"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Folosiți blocarea ecranului sau blocarea facială"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Folosiți deblocarea facială pentru a continua"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Pictograma chip"</string> @@ -1998,8 +1988,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Știri și reviste"</string> <string name="app_category_maps" msgid="6395725487922533156">"Hărți și navigare"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productivitate"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Accesibilitate"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Stocare pe dispozitiv"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Remedierea erorilor prin USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"oră"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 1a513e462580..48f96ef3d289 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -556,23 +556,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Приложение сможет вносить изменения в вашу фотоколлекцию."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"доступ к геоданным в медиаколлекции"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Приложение получит доступ к геоданным в вашей медиаколлекции."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Использовать биометрию"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Использовать биометрию или блокировку экрана"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Подтвердите, что это вы"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Чтобы продолжить, используйте биометрические данные"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрическое оборудование недоступно"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аутентификация отменена"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Не распознано"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Аутентификация отменена"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Укажите PIN-код, пароль или графический ключ"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Ошибка аутентификации."</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Использовать блокировку экрана"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Чтобы продолжить, введите учетные данные устройства"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Отсканирована только часть отпечатка. Повторите попытку."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Не удалось распознать отпечаток. Повторите попытку."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Очистите сканер и повторите попытку."</string> @@ -595,10 +590,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На этом устройстве нет сканера отпечатков пальцев."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сканер отпечатков пальцев временно отключен."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Отпечаток <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Использовать отпечаток пальца"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Использовать отпечаток пальца или блокировку экрана"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Чтобы продолжить, используйте цифровой отпечаток"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -644,12 +637,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Это устройство не поддерживает функцию \"Фейсконтроль\"."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик временно отключен."</string> <string name="face_name_template" msgid="3877037340223318119">"Лицо <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Использовать фейсконтроль"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Использовать фейсконтроль или блокировку экрана"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Чтобы продолжить, используйте фейсконтроль"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Значок лица"</string> @@ -2030,8 +2020,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Новости и журналы"</string> <string name="app_category_maps" msgid="6395725487922533156">"Карты и навигация"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Работа"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Доступность"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Хранилище устройства"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Отладка по USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ч."</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 011b042f81b3..f645fe10f3bc 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -556,23 +556,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Umožňuje aplikácii upravovať zbierku fotiek."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"čítať polohy zo zbierky médií"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Umožňuje aplikácii čítať polohy zo zbierky médií."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Použiť biometrické údaje"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Použiť biometrické údaje alebo zámku obrazovky"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Overenie, že ste to vy"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Ak chcete pokračovať, použite biometrický údaj"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrický hardvér nie je k dispozícii"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Overenie bolo zrušené"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Nerozpoznané"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Overenie bolo zrušené"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nie je nastavený PIN, vzor ani heslo"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Chyba overenia"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Použiť zámku obrazovky"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Ak chcete pokračovať, zadajte prihlasovacie údaje zariadenia"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Podarilo sa rozpoznať iba časť odtlačku prsta. Skúste to znova."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Odtlačok prsta sa nepodarilo spracovať. Skúste to znova."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Očistite senzor odtlačkov prstov a skúste to znova."</string> @@ -595,10 +590,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zariadenie nemá senzor odtlačkov prstov."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasne vypnutý."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst: <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Použiť odtlačok prsta"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Použiť odtlačok prsta alebo zámku obrazovky"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Pokračujte nasnímaním odtlačku prsta"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -644,12 +637,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Toto zariadenie nepodporuje odomknutie tvárou."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je dočasne vypnutý."</string> <string name="face_name_template" msgid="3877037340223318119">"Tvár <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Použiť odomknutie tvárou"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Použiť tvár alebo zámku obrazovky"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Ak chcete pokračovať, použite odomknutie tvárou"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona tváre"</string> @@ -2030,8 +2020,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Noviny a časopisy"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mapy a navigácia"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Kancelárske"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Dostupnosť"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Úložisko zariadenia"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Ladenie cez USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"hodina"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 0a7f7600abfc..97de6a370883 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -556,23 +556,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Aplikaciji omogoča spreminjanje zbirke fotografij."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"branje lokacij v predstavnostni zbirki"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Aplikaciji omogoča branje lokacij v predstavnostni zbirki."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Uporaba biometrike"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Uporaba biometrike ali odklepanja s poverilnico"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Preverite, da ste res vi"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Za nadaljevanje uporabite biometrični podatek."</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Strojna oprema za biometrične podatke ni na voljo"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Preverjanje pristnosti je preklicano"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Ni prepoznano"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Preverjanje pristnosti je preklicano"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nastavljena ni nobena koda PIN, vzorec ali geslo"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Napaka pri preverjanju pristnosti"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Uporaba odklepanja s poverilnico"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Za nadaljevanje vnesite poverilnico za napravo."</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Zaznan delni prstni odtis. Poskusite znova."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Prstnega odtisa ni bilo mogoče obdelati. Poskusite znova."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Tipalo prstnih odtisov je umazano. Očistite ga in poskusite znova."</string> @@ -595,10 +590,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ta naprava nima tipala prstnih odtisov."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tipalo je začasno onemogočeno."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Uporaba prstnega odtisa"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Uporaba prstnega odtisa ali odklepanja s poverilnico"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Uporabite prstni odtis, če želite nadaljevati."</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -644,12 +637,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ta naprava ne podpira odklepanja z obrazom."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Tipalo je začasno onemogočeno."</string> <string name="face_name_template" msgid="3877037340223318119">"Obraz <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Uporaba odklepanja z obrazom"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Uporaba odklepanja z obrazom ali s poverilnico"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Za nadaljevanje uporabite odklepanje z obrazom."</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona obraza"</string> @@ -2030,8 +2020,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Novice in revije"</string> <string name="app_category_maps" msgid="6395725487922533156">"Zemljevidi in navigacija"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Storilnost"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Funkc. za ljudi s poseb. potreb."</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Shramba naprave"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Odpravljanje težav prek povezave USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ura"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index ddce26d68e59..a78ff777258e 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Lejon aplikacionin të modifikojë koleksionin tënd të fotografive."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lexo vendndodhjet nga koleksioni yt i medias"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Lejon aplikacionin të lexojë vendndodhjet nga koleksioni yt i medias."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Përdor sistemet biometrike"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Përdor sistemet biometrike ose kyçjen e ekranit"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifiko që je ti"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Përdor sistemet e tua biometrike për të vazhduar"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Nuk ofrohet harduer biometrik"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Vërtetimi u anulua"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Nuk njihet"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Vërtetimi u anulua"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nuk është vendosur kod PIN, motiv ose fjalëkalim"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Gabim gjatë vërtetimit"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Përdor kyçjen e ekranit"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Fut kredencialet e pajisjes për të vazhduar"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"U zbulua një gjurmë gishti e pjesshme. Provo përsëri."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Gjurma e gishtit nuk mund të përpunohej. Provo përsëri."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Sensori i gjurmës së gishtit nuk është i pastër. Pastroje dhe provo përsëri."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kjo pajisje nuk ka sensor të gjurmës së gishtit."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensori është çaktivizuar përkohësisht."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Gishti <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Përdor gjurmën e gishtit"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Përdor gjurmën e gishtit ose kyçjen e ekranit"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Përdor gjurmën e gishtit për të vazhduar"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Shkyçja me fytyrë nuk mbështetet në këtë pajisje"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensori është çaktivizuar përkohësisht."</string> <string name="face_name_template" msgid="3877037340223318119">"Fytyra <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Përdor shkyçjen me fytyrë"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Përdor kyçjen me fytyrë ose kyçjen e ekranit"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Përdor shkyçjen me fytyrë për të vazhduar"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona e fytyrës"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Lajme dhe revista"</string> <string name="app_category_maps" msgid="6395725487922533156">"Harta dhe navigim"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktivitet"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Qasshmëria"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Hapësira ruajtëse e pajisjes"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Korrigjimi përmes USB-së"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"orë"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 11d5e7d8c43c..04bc35f5a2d1 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -553,23 +553,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Дозвољава апликацији да мења колекцију слика."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"читање локација из медијске колекције"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Дозвољава апликацији да чита локације из медијске колекције."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Користите биометрију"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Користите биометрију или закључавање екрана"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Потврдите свој идентитет"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Користите биометријски податак да бисте наставили"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометријски хардвер није доступан"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Потврда идентитета је отказана"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Није препознато"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Потврда идентитета је отказана"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Нисте подесили ни PIN, ни шаблон, ни лозинку"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Грешка при потврди идентитета"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Користите закључавање екрана"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Унесите акредитив за уређај да бисте наставили"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Откривен је делимични отисак прста. Пробајте поново."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Није успела обрада отиска прста. Пробајте поново."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Сензор за отиске прстију је прљав. Очистите га и покушајте поново."</string> @@ -592,10 +587,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Овај уређај нема сензор за отисак прста."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензор је привремено онемогућен."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Користите отисак прста"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Користите отисак прста или закључавање екрана"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Наставите помоћу отиска прста"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -641,12 +634,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Откључавање лицем није подржано на овом уређају"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Сензор је привремено онемогућен."</string> <string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Користите откључавање лицем"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Користите закључавање лицем или закључавање екрана"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Користите откључавање лицем да бисте наставили"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Икона лица"</string> @@ -1998,8 +1988,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Новости и часописи"</string> <string name="app_category_maps" msgid="6395725487922533156">"Мапе и навигација"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Продуктивност"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Приступачност"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Меморијски простор уређаја"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Отклањање грешака са USB-а"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"сат"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 4f6ccff5313f..5ab243a042e1 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Tillåter att appen gör ändringar i din fotosamling."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"läsa av platser i din mediesamling"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Tillåter att appen läser av platser i din mediesamling."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Använd biometri"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Använd biometrisk data eller skärmlåset"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifiera din identitet"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Fortsätt med hjälp av din biometriska data"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk maskinvara är inte tillgänglig"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentiseringen avbröts"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Identifierades inte"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentiseringen avbröts"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pinkod, grafiskt lösenord eller lösenord har inte angetts"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Ett fel uppstod vid autentiseringen"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Använd skärmlåset"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Fortsätt genom att ange enhetens autentiseringsuppgifter"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Ofullständigt fingeravtryck. Försök igen."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Det gick inte att bearbeta fingeravtrycket. Försök igen."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingeravtryckssensorn är smutsig. Rengör den och försök igen."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Enheten har ingen fingeravtryckssensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensorn har tillfälligt inaktiverats."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Använd ditt fingeravtryck"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Använd ditt fingeravtryck eller skärmlåset"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Fortsätt med hjälp av ditt fingeravtryck"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansiktslås stöds inte på den här enheten."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensorn har tillfälligt inaktiverats."</string> <string name="face_name_template" msgid="3877037340223318119">"Ansikte <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Använd ansiktslåset"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Använd ansiktslåset eller skärmlåset"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Fortsätt med hjälp av ansiktslåset"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Ansikte"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Nyheter och tidskrifter"</string> <string name="app_category_maps" msgid="6395725487922533156">"Kartor och navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Produktivitet"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Tillgänglighet"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Enhetens lagringsutrymme"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-felsökning"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"timme"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 8dd721f8890a..00477d1b1f5f 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Inaruhusu programu kubadilisha mkusanyiko wa picha zako."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"kusoma maeneo kwenye mkusanyiko wa vipengee vyako"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Inaruhusu programu kusoma maeneo kwenye mkusanyiko wa vipengee vyako."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Tumia bayometriki"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Tumia bayometriki au mbinu ya kufunga skrini"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Thibitisha kuwa ni wewe"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Tumia bayometriki yako ili uendelee"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Maunzi ya bayometriki hayapatikani"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Imeghairi uthibitishaji"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Hayatambuliki"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Imeghairi uthibitishaji"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Hujaweka pin, mchoro au nenosiri"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Hitilafu imetokea wakati wa uthibitishaji"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Tumia mbinu ya kufunga skrini"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Weka kitambulisho cha kifaa chako ili uendelee."</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Kitambua alama kimetambua sehemu ya alama. Tafadhali jaribu tena."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Imeshindwa kuchakata alama ya kidole. Tafadhali jaribu tena."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Kitambua alama ya kidole ni kichafu. Tafadhali kisafishe na ujaribu tena."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kifaa hiki hakina kitambua alama ya kidole."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Kitambuzi kimezimwa kwa muda."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Kidole cha <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Tumia alama ya kidole"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Tumia alama ya kidole au mbinu ya kufunga skrini"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Tumia alama ya kidole chako ili uendelee"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Kufungua kwa uso hakutumiki kwenye kifaa hiki."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Kitambuzi kimezimwa kwa muda."</string> <string name="face_name_template" msgid="3877037340223318119">"Uso wa <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Tumia kipengele cha kufungua kwa uso"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Tumia uso au mbinu ya kufunga skrini"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Tumia kipengele cha kufungua kwa uso ili uendelee"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Aikoni ya uso"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Habari na Magazeti"</string> <string name="app_category_maps" msgid="6395725487922533156">"Ramani na Maelekezo"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Uzalishaji"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Ufikivu"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Hifadhi ya kifaa"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Utatuzi wa USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"saa"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 3760c6dc73c5..6325c191eea3 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"உங்களின் படத் தொகுப்பை மாற்ற ஆப்ஸை அனுமதிக்கும்."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"மீடியா தொகுப்பிலிருந்து இடங்களை அறிதல்"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"உங்களின் மீடியா தொகுப்பிலிருந்து இடங்களை அறிந்துகொள்ள ஆப்ஸை அனுமதிக்கும்."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"பயோமெட்ரிக்ஸைப் பயன்படுத்து"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"பயோமெட்ரிக்ஸையோ திரைப் பூட்டையோ பயன்படுத்து"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"நீங்கள்தான் என உறுதிசெய்க"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"தொடர உங்கள் பயோமெட்ரிக்கைப் பயன்படுத்துங்கள்"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"பயோமெட்ரிக் வன்பொருள் இல்லை"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"அங்கீகரிப்பு ரத்தானது"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"அடையாளங்காணபடவில்லை"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"அங்கீகரிப்பு ரத்தானது"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"பின்னோ, பேட்டர்னோ, கடவுச்சொல்லோ அமைக்கப்படவில்லை"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"அங்கீகரிப்பதில் பிழை"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"திரைப் பூட்டைப் பயன்படுத்து"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"தொடர, சாதன அனுமதிச் சான்றை உள்ளிடுங்கள்"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"கைரேகையை ஓரளவுதான் கண்டறிய முடிந்தது. மீண்டும் முயலவும்."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"கைரேகையைச் செயலாக்க முடியவில்லை. மீண்டும் முயலவும்."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"கைரேகை சென்சாரில் தூசி உள்ளது. சுத்தம் செய்து, முயலவும்."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"இந்தச் சாதனத்தில் கைரேகை சென்சார் இல்லை."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"சென்சார் தற்காலிகமாக முடக்கப்பட்டுள்ளது."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"கைரேகை <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"கைரேகையைப் பயன்படுத்து"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"கைரேகையையோ திரைப் பூட்டையோ பயன்படுத்து"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"தொடர்வதற்கு கைரேகையைப் பயன்படுத்துங்கள்"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"இந்த சாதனத்தில் ’முகம் காட்டித் திறத்தல்’ ஆதரிக்கப்படவில்லை."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"சென்சார் தற்காலிகமாக முடக்கப்பட்டுள்ளது."</string> <string name="face_name_template" msgid="3877037340223318119">"முகம் <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"முகம் காட்டித் திறத்தலை உபயோகி"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"முகத்தையோ திரைப் பூட்டையோ பயன்படுத்து"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"தொடர, \'முகம் காட்டித் திறத்தல்\' அம்சத்தை உபயோகியுங்கள்"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"முக ஐகான்"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"செய்திகளும் பத்திரிகைகளும்"</string> <string name="app_category_maps" msgid="6395725487922533156">"வரைபடங்களும் வழிசெலுத்தலும்"</string> <string name="app_category_productivity" msgid="1844422703029557883">"உற்பத்தித்திறன்"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"அணுகல்தன்மை"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"சாதனச் சேமிப்பகம்"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB பிழைதிருத்தம்"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"மணி"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 63ee3a0374af..c2a5d42b6a25 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"మీ ఫోటో సేకరణను సవరించడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవండి"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవడానికి యాప్ను అనుమతిస్తుంది."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"బయోమెట్రిక్స్ను ఉపయోగించండి"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"బయోమెట్రిక్స్ను లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ఇది మీరేనని వెరిఫై చేసుకోండి"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"కొనసాగించడానికి, మీ బయోమెట్రిక్ను ఉపయోగించండి"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"బయోమెట్రిక్ హార్డ్వేర్ అందుబాటులో లేదు"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"ప్రమాణీకరణ రద్దు చేయబడింది"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"గుర్తించలేదు"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"ప్రమాణీకరణ రద్దు చేయబడింది"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"పిన్, ఆకృతి లేదా పాస్వర్డ్ సెట్ చేయబడలేదు"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"ప్రామాణీకరిస్తున్నప్పుడు ఎర్రర్ ఏర్పడింది"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"స్క్రీన్ లాక్ను ఉపయోగించండి"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"కొనసాగడానికి, మీ పరికర ఆధారాలను ఎంటర్ చేయండి"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"పాక్షిక వేలిముద్ర గుర్తించబడింది. దయచేసి మళ్లీ ప్రయత్నించండి."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"వేలిముద్రను ప్రాసెస్ చేయడం సాధ్యపడలేదు. దయచేసి మళ్లీ ప్రయత్నించండి."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"వేలిముద్ర సెన్సార్ మురికిగా ఉంది. దయచేసి శుభ్రపరిచి, మళ్లీ ప్రయత్నించండి."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ఈ పరికరంలో వేలిముద్ర సెన్సార్ ఎంపిక లేదు."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"సెన్సార్ తాత్కాలికంగా డిజేబుల్ చేయబడింది."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"వేలు <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"వేలిముద్రను ఉపయోగించండి"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"వేలిముద్ర లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"కొనసాగించడానికి మీ వేలిముద్రను ఉపయోగించండి"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"ఈ పరికరంలో ముఖంతో అన్లాక్ను ఉపయోగించడానికి మద్దతు లేదు."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"సెన్సార్ తాత్కాలికంగా డిజేబుల్ చేయబడింది."</string> <string name="face_name_template" msgid="3877037340223318119">"ముఖ <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"ఫేస్ అన్లాక్ను ఉపయోగించండి"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ముఖం లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"కొనసాగించడానికి, మీ ఫేస్ అన్లాక్ను ఉపయోగించండి"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"ముఖ చిహ్నం"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"వార్తలు & వార్తాపత్రికలు"</string> <string name="app_category_maps" msgid="6395725487922533156">"Maps & నావిగేషన్"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ఉత్పాదకత"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"యాక్సెసిబిలిటీ"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"పరికర నిల్వ"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB డీబగ్గింగ్"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"గంట"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 3c985b999162..a5cfe4028a39 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"อนุญาตให้แอปแก้ไขคอลเล็กชันรูปภาพของคุณ"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"อ่านตำแหน่งจากคอลเล็กชันสื่อของคุณ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"อนุญาตให้แอปอ่านตำแหน่งจากคอลเล็กชันสื่อของคุณ"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"ใช้ข้อมูลไบโอเมตริก"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ใช้ข้อมูลไบโอเมตริกหรือการล็อกหน้าจอ"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ยืนยันว่าเป็นตัวคุณ"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ใช้ข้อมูลไบโอเมตริกเพื่อดำเนินการต่อ"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ฮาร์ดแวร์ไบโอเมตริกไม่พร้อมใช้งาน"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"ยกเลิกการตรวจสอบสิทธิ์แล้ว"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"ไม่รู้จัก"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"ยกเลิกการตรวจสอบสิทธิ์แล้ว"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ไม่ได้ตั้ง PIN, รูปแบบ หรือรหัสผ่าน"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"การตรวจสอบข้อผิดพลาด"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ใช้การล็อกหน้าจอ"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"ป้อนข้อมูลเข้าสู่ระบบอุปกรณ์เพื่อดำเนินการต่อ"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ตรวจพบลายนิ้วมือเพียงบางส่วน โปรดลองอีกครั้ง"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ประมวลผลลายนิ้วมือไม่ได้ โปรดลองอีกครั้ง"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"เซ็นเซอร์ลายนิ้วมือไม่สะอาด โปรดทำความสะอาดและลองอีกครั้ง"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"อุปกรณ์นี้ไม่มีเซ็นเซอร์ลายนิ้วมือ"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"นิ้ว <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ใช้ลายนิ้วมือ"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ใช้ลายนิ้วมือหรือการล็อกหน้าจอ"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ใช้ลายนิ้วมือของคุณเพื่อดำเนินการต่อ"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"อุปกรณ์นี้ไม่รองรับการปลดล็อกด้วยใบหน้า"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string> <string name="face_name_template" msgid="3877037340223318119">"ใบหน้า <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"ใช้การปลดล็อกด้วยใบหน้า"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ใช้การล็อกด้วยใบหน้าหรือการล็อกหน้าจอ"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"ใช้การปลดล็อกด้วยใบหน้าเพื่อดำเนินการต่อ"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"ไอคอนใบหน้า"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"ข่าวสารและนิตยสาร"</string> <string name="app_category_maps" msgid="6395725487922533156">"แผนที่และการนำทาง"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ประสิทธิภาพการทำงาน"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"การช่วยเหลือพิเศษ"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"พื้นที่เก็บข้อมูลของอุปกรณ์"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"การแก้ไขข้อบกพร่อง USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ชั่วโมง"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 7402195a0de8..4829cefe1940 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Pinapayagan ang app na baguhin ang iyong koleksyon ng larawan."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"basahin ang mga lokasyon mula sa iyong koleksyon ng media"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Pinapayagan ang app na basahin ang mga lokasyon mula sa iyong koleksyon ng media."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Gumamit ng biometrics"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gumamit ng biometrics o lock ng screen"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"I-verify na ikaw ito"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Gamitin ang iyong biometric para magpatuloy"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Walang biometric hardware"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Nakansela ang pag-authenticate"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Hindi nakilala"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Nakansela ang pag-authenticate"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Walang itinakdang pin, pattern, o password"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Nagkaroon ng error sa pag-authenticate"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Gumamit ng lock ng screen"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Ilagay ang kredensyal ng device para magpatuloy"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Hindi buo ang natukoy na fingerprint. Pakisubukan ulit."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Hindi maproseso ang fingerprint. Pakisubukan ulit."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Marumi ang sensor ng fingerprint. Pakilinis at subukang muli."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Walang sensor ng fingerprint ang device na ito."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Pansamantalang na-disable ang sensor."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Daliri <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gumamit ng fingerprint"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gumamit ng fingerprint o lock ng screen"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gamitin ang iyong fingerprint para magpatuloy"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Hindi sinusuportahan ang face unlock sa device na ito."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Pansamantalang na-disable ang sensor."</string> <string name="face_name_template" msgid="3877037340223318119">"Mukha <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Gumamit ng face unlock"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gumamit ng mukha o lock ng screen"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Gumamit ng face unlock para magpatuloy"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Balita at Mga Magazine"</string> <string name="app_category_maps" msgid="6395725487922533156">"Mga Mapa at Navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Productivity"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Pagiging Accessible"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Storage ng device"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Pag-debug ng USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"oras"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 147553fbfa0a..186ffa7c8206 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Uygulamanın fotoğraf koleksiyonunuzu değiştirmesine izin verir."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"medya koleksiyonunuzdaki konumları okuma"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Uygulamanın medya koleksiyonunuzdaki konumları okumasına izin verir."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biyometri kullan"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biyometri veya ekran kilidi kullan"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Siz olduğunuzu doğrulayın"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Devam etmek için biyometri kullanın"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biyometrik donanım kullanılamıyor"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Kimlik doğrulama iptal edildi"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Tanınmadı"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Kimlik doğrulama iptal edildi"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN, desen veya şifre seti yok"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Kimlik doğrulama sırasında hata oluştu"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ekran kilidi kullan"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Devam etmek için cihaz kimlik bilginizi girin"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Parmak izinin tümü algılanamadı. Lütfen tekrar deneyin."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Parmak izi işlenemedi. Lütfen tekrar deneyin."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Parmak izi sensörü kirli. Lütfen temizleyin ve tekrar deneyin."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda parmak izi sensörü yok."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensör geçici olarak devre dışı bırakıldı."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. parmak"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Parmak izi kullan"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Parmak izi veya ekran kilidi kullan"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Devam etmek için parmak izinizi kullanın"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Bu cihazda yüz tanıma kilidi desteklenmiyor"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensör geçici olarak devre dışı bırakıldı."</string> <string name="face_name_template" msgid="3877037340223318119">"Yüz <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Yüz tanıma kilidi kullan"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Yüz tanıma veya ekran kilidi kullan"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Devam etmek için yüz tanıma kilidini kullanın"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Yüz simgesi"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Haberler ve Dergiler"</string> <string name="app_category_maps" msgid="6395725487922533156">"Haritalar ve Navigasyon"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Verimlilik"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Erişilebilirlik"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Cihazdaki depolama alanı"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB üzerinden hata ayıklama"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"saat"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 77e664afcbfe..7049a2e11110 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -556,23 +556,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Додаток зможе змінювати вашу колекцію фотографій."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"розпізнавати геодані з колекції медіа-вмісту"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Додаток зможе розпізнавати геодані з вашої колекції медіа-вмісту."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Використовувати біометрію"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Використовувати біометрію або блокування екрана"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Підтвердьте, що це ви"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Щоб продовжити, скористайтеся біометрією"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Біометричне апаратне забезпечення недоступне"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Автентифікацію скасовано"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Не розпізнано"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Автентифікацію скасовано"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Не вказано PIN-код, ключ або пароль"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Помилка автентифікації"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Використовувати блокування екрана"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Щоб продовжити, введіть облікові дані пристрою"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Відбиток пальця розпізнано частково. Повторіть спробу."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Не вдалось обробити відбиток пальця. Повторіть спробу."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Датчик відбитків пальців забруднився. Очистьте його та повторіть спробу."</string> @@ -595,10 +590,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На цьому пристрої немає сканера відбитків пальців."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик тимчасово вимкнено."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Відбиток пальця <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Використовувати відбиток пальця"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Використовувати відбиток пальця або блокування екрана"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Щоб продовжити, скористайтеся своїм відбитком пальця"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -644,12 +637,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"На цьому пристрої не підтримується Фейсконтроль."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик тимчасово вимкнено."</string> <string name="face_name_template" msgid="3877037340223318119">"Обличчя <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Використовувати фейсконтроль"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Використовувати фейсконтроль або блокування екрана"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Щоб продовжити, скористайтеся фейсконтролем"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Значок обличчя"</string> @@ -2030,8 +2020,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Новини та журнали"</string> <string name="app_category_maps" msgid="6395725487922533156">"Карти й навігація"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Продуктивність"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Спеціальні можливості"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Пам’ять пристрою"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Налагодження USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"години"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 10f787b70fd1..615e2fa4a831 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"ایپ کو آپ کی تصویر کے مجموعے میں ترمیم کی اجازت دیتا ہے۔"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"اپنی میڈيا کے مجموعے سے مقامات پڑھیں"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"ایپ کو آپ کی میڈيا کے مجموعے سے مقامات پڑھنے کی اجازت دیتا ہے۔"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"بایو میٹرکس استعمال کریں"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"بایو میٹرکس یا اسکرین لاک استعمال کریں"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"توثیق کریں کہ یہ آپ ہیں"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"جاری رکھنے کیلئے اپنا بایو میٹرک استعمال کریں"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"بایومیٹرک ہارڈ ویئر دستیاب نہیں ہے"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"تصدیق کا عمل منسوخ ہو گیا"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"تسلیم شدہ نہیں ہے"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"تصدیق کا عمل منسوخ ہو گیا"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"کوئی پن، پیٹرن، یا پاس ورڈ سیٹ نہیں ہے"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"خرابی کی توثیق ہو رہی ہے"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"اسکرین لاک استعمال کریں"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"جاری رکھنے کیلئے اپنے آلے کی سند درج کریں"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"جزوی فنگر پرنٹ کی شناخت ہوئی۔ براہ کرم دوبارہ کوشش کریں۔"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"فنگر پرنٹ پر کارروائی نہیں کی جا سکی۔ براہ کرم دوبارہ کوشش کریں۔"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"فنگر پرنٹ سینسر گندا ہے۔ براہ کرم صاف کریں اور دوبارہ کوشش کریں۔"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"اس آلہ میں فنگر پرنٹ سینسر نہیں ہے۔"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"سینسر عارضی طور غیر فعال ہے۔"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"انگلی <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"فنگر پرنٹ استعمال کریں"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"فنگر پرنٹ یا اسکرین لاک استعمال کریں"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"جاری رکھنے کیلئے اپنا فنگر پرنٹ استعمال کریں"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"اس آلہ پر چہرے کے ذریعے غیر مقفل کرنا تعاون یافتہ نہیں ہے۔"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"سینسر عارضی طور غیر فعال ہے۔"</string> <string name="face_name_template" msgid="3877037340223318119">"چہرہ <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"چہرے کے ذریعے غیر مقفل کرنا استعمال کریں"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"چہرہ یا اسکرین لاک استعمال کریں"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"جاری رکھنے کیلئے چہرے کے ذریعے غیر مقفل کرنا استعمال کریں"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"چہرے کا آئیکن"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"خبریں اور میگزین"</string> <string name="app_category_maps" msgid="6395725487922533156">"نقشے اور نیویگیشن"</string> <string name="app_category_productivity" msgid="1844422703029557883">"پروڈکٹیوٹی"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"ایکسیسبیلٹی"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"آلہ کی اسٹوریج"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ڈیبگ کرنا"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"گھنٹہ"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index f2c5589f392b..0bcba068ffa3 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -553,7 +553,7 @@ <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometrik tasdiqlash"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrika yoki ekran qulfi"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Oʻzingizni taniting"</string> - <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Davob etish uchun biometrik tasdiqlang"</string> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Davom etish uchun biometrik tasdiqlang"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrik sensor ishlamayapti"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikatsiya bekor qilindi"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Aniqlanmadi"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 4d7091c68696..11644d6dba9a 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Cho phép ứng dụng này sửa đổi bộ sưu tập ảnh của bạn."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"đọc vị trí từ bộ sưu tập phương tiện"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Cho phép ứng dụng này đọc vị trí từ bộ sưu tập phương tiện của bạn."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Dùng dữ liệu sinh trắc học"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Dùng dữ liệu sinh trắc học hoặc phương thức khóa màn hình"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Xác minh danh tính của bạn"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Dùng dữ liệu sinh trắc học của bạn để tiếp tục"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Không có phần cứng sinh trắc học"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Đã hủy xác thực"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Không nhận dạng được"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Đã hủy xác thực"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Chưa đặt mã PIN, hình mở khóa hoặc mật khẩu"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Lỗi khi xác thực"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Dùng phương thức khóa màn hình"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Nhập thông tin xác thực thiết bị của bạn để tiếp tục"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Đã phát hiện được một phần vân tay. Vui lòng thử lại."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Không thể xử lý vân tay. Vui lòng thử lại."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Cảm biến vân tay bị bẩn. Hãy làm sạch và thử lại."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Thiết bị này không có cảm biến vân tay."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Đã tạm thời tắt cảm biến."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Ngón tay <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Dùng vân tay"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Dùng vân tay hoặc phương thức khóa màn hình"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Sử dụng dấu vân tay của bạn để tiếp tục"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"Thiết bị này không hỗ trợ tính năng mở khóa bằng khuôn mặt."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Đã tạm thời tắt cảm biến."</string> <string name="face_name_template" msgid="3877037340223318119">"Khuôn mặt <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Dùng tính năng mở khóa bằng khuôn mặt"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Dùng khuôn mặt hoặc phương thức khóa màn hình"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Dùng tính năng mở khóa bằng khuôn mặt để tiếp tục"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Biểu tượng khuôn mặt"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Tin tức và tạp chí"</string> <string name="app_category_maps" msgid="6395725487922533156">"Bản đồ và dẫn đường"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Sản xuất"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Hỗ trợ tiếp cận"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Bộ nhớ của thiết bị"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Gỡ lỗi qua USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"giờ"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 1f8f1766b376..ec455bc07ab0 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"允许该应用修改您的照片收藏。"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"从您的媒体收藏中读取位置信息"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"允许该应用从您的媒体收藏中读取位置信息。"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"使用生物识别"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"使用生物识别或屏幕锁定凭据"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"验证是您本人在操作"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"使用生物识别验证身份才能继续"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"生物识别硬件无法使用"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"身份验证已取消"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"无法识别"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"身份验证已取消"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"未设置任何 PIN 码、图案和密码"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"进行身份验证时出错"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"使用屏幕锁定凭据"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"输入您的设备凭据才能继续"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"仅检测到部分指纹,请重试。"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"无法处理指纹,请重试。"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"指纹传感器有脏污。请擦拭干净,然后重试。"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此设备没有指纹传感器。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"传感器已暂时停用。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"使用指纹"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"使用指纹或屏幕锁定凭据"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"使用指纹完成验证才能继续"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"此设备不支持人脸解锁。"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"传感器已暂时停用。"</string> <string name="face_name_template" msgid="3877037340223318119">"面孔 <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"使用人脸解锁"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"使用人脸解锁或屏幕锁定凭据"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"使用人脸解锁验证身份才能继续"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"面孔图标"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"新闻和杂志"</string> <string name="app_category_maps" msgid="6395725487922533156">"地图和导航"</string> <string name="app_category_productivity" msgid="1844422703029557883">"办公"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"无障碍"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"设备存储空间"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB 调试"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"点"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index ebc02c502b8a..16b9b0fe31e4 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"允許應用程式修改您的相片集。"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"讀取媒體集的位置"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"允許應用程式讀取媒體集的位置。"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"使用生物識別"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"使用生物識別或螢幕鎖定"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"驗證是你本人"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"如要繼續操作,請使用使用生物識別驗證身分"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"無法使用生物識別硬件"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"已取消驗證"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"未能識別"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"已取消驗證"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"未設定 PIN、圖案或密碼"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"驗證時發生錯誤"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"使用螢幕鎖定"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"如要繼續操作,請輸入裝置憑證"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"只偵測到部分指紋。請再試一次。"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"無法處理指紋。請再試一次。"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"指紋感應器不乾淨。請清潔後再試一次。"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此裝置沒有指紋感應器。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"使用指紋鎖定"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"使用指紋或螢幕鎖定"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"請使用您的指紋繼續"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"此裝置不支援「臉孔解鎖」。"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"感應器已暫時停用。"</string> <string name="face_name_template" msgid="3877037340223318119">"臉孔 <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"使用臉孔解鎖"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"使用臉孔或螢幕鎖定"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"如要繼續操作,請使用臉孔解鎖驗證身分"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"臉孔圖示"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"新聞和雜誌"</string> <string name="app_category_maps" msgid="6395725487922533156">"地圖和導航"</string> <string name="app_category_productivity" msgid="1844422703029557883">"生產力應用程式"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"無障礙功能"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"裝置儲存空間"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB 偵錯"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"時"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 10d05c1fa14d..90fe15d144c4 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"允許應用程式修改你的相片收藏。"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"讀取你的媒體收藏的位置資訊"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"允許應用程式讀取你的媒體收藏的位置資訊。"</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"使用生物特徵辨識功能"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"使用生物特徵辨識或螢幕鎖定功能"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"驗證你的身分"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"如要繼續操作,請使用生物特徵辨識功能驗證身分"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"無法使用生物特徵辨識硬體"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"已取消驗證"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"無法辨識"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"已取消驗證"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"未設定 PIN 碼、解鎖圖案或密碼"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"驗證時發生錯誤"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"使用螢幕鎖定功能"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"如要繼續操作,請輸入裝置憑證"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"僅偵測到部分指紋,請再試一次。"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"無法處理指紋,請再試一次。"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"指紋感應器有髒汙。請清潔感應器,然後再試一次。"</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"這個裝置沒有指紋感應器。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"使用指紋"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"使用指紋或螢幕鎖定功能"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"使用指紋完成驗證才能繼續操作"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"這個裝置不支援人臉解鎖功能。"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"感應器已暫時停用。"</string> <string name="face_name_template" msgid="3877037340223318119">"臉孔 <xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"使用人臉解鎖功能"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"使用人臉解鎖或螢幕鎖定功能"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"如要繼續操作,請使用人臉解鎖功能驗證身分"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"臉孔圖示"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"新聞和雜誌"</string> <string name="app_category_maps" msgid="6395725487922533156">"地圖和導航"</string> <string name="app_category_productivity" msgid="1844422703029557883">"工作效率"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"無障礙工具"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"裝置儲存空間"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB 偵錯"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"點"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 976b97a2b8ed..1089f1e4b1c5 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -550,23 +550,18 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Ivumela uhlelo lwakho lokusebenza ukuthi lilungise iqoqo lakho lesithombe."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"funda izindawo kusukela kuqoqo lakho lemidiya"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Ivumela uhlelo lokusebenza ukuthi lifunde izindawo kusukela kuqoqo lakho lemidiya."</string> - <!-- no translation found for biometric_app_setting_name (3339209978734534457) --> - <skip /> - <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) --> - <skip /> + <string name="biometric_app_setting_name" msgid="3339209978734534457">"Sebenzisa i-biometrics"</string> + <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Sebenzisa i-biometrics noma ukukhiya isikrini"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Qinisekisa ukuthi nguwe"</string> - <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) --> - <skip /> + <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Sebenzisa i-biometric yakho ukuze uqhubeke"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"I-Biometric hardware ayitholakali"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ukufakazela ubuqiniso kukhanseliwe"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"Akwaziwa"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Ukufakazela ubuqiniso kukhanseliwe"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ayikho iphinikhodi, iphethini, noma iphasiwedi esethiwe"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"Iphutha lokufakazela ubuqiniso"</string> - <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) --> - <skip /> - <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) --> - <skip /> + <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Sebenzisa isikhiya sesikrini"</string> + <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Faka izifakazelo zedivayisi yakho ukuze uqhubeke"</string> <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Izigxivizo zeminwe ezincane zitholiwe. Sicela uzame futhi."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Ayikwazanga ukucubungula izigxivizo zeminwe. Sicela uzame futhi."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Inzwa yezigxivizo zeminwe ingcolile. Sicela uyihlanze uphinde uzame futhi."</string> @@ -589,10 +584,8 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Le divayisi ayinayo inzwa yezigxivizo zeminwe."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Inzwa ikhutshazwe okwesikhashana."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Umunwe ongu-<xliff:g id="FINGERID">%d</xliff:g>"</string> - <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) --> - <skip /> - <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) --> - <skip /> + <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Sebenzisa izigxivizo zeminwe"</string> + <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Sebenzisa izigxivizo zeminwe noma ukukhiya isikrini"</string> <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Sebenzisa izigxivizo zakho zeminwe ukuze uqhubeke"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -638,12 +631,9 @@ <string name="face_error_hw_not_present" msgid="1070600921591729944">"I-face unlock ayisekelwe kule divayisi."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Inzwa ikhutshazwe okwesikhashana."</string> <string name="face_name_template" msgid="3877037340223318119">"Ubuso be-<xliff:g id="FACEID">%d</xliff:g>"</string> - <!-- no translation found for face_app_setting_name (8130135875458467243) --> - <skip /> - <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) --> - <skip /> - <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) --> - <skip /> + <string name="face_app_setting_name" msgid="8130135875458467243">"Sebenzisa i-face unlock"</string> + <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Sebenzisa i-face lock noma ukukhiya isikrini"</string> + <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Sebenzisa i-face unlock ukuze uqhubeke"</string> <string-array name="face_error_vendor"> </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Isithonjana sobuso"</string> @@ -1966,8 +1956,7 @@ <string name="app_category_news" msgid="1172762719574964544">"Izindaba nomagazini"</string> <string name="app_category_maps" msgid="6395725487922533156">"Amamephu nokuzula"</string> <string name="app_category_productivity" msgid="1844422703029557883">"Ukukhiqiza"</string> - <!-- no translation found for app_category_accessibility (6643521607848547683) --> - <skip /> + <string name="app_category_accessibility" msgid="6643521607848547683">"Ukufinyeleleka"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Isitoreji sedivayisi"</string> <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Ukulungisa iphutha le-USB"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ihora"</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index e0a116be371c..7c446a90b06f 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3564,6 +3564,16 @@ <attr name="__removed2" format="boolean" /> <!-- Specifies whether the IME supports showing inline suggestions. --> <attr name="supportsInlineSuggestions" format="boolean" /> + <!-- Specify one or more configuration changes that the IME will handle itself. If not + specified, the IME will be restarted if any of these configuration changes happen in + the system. Otherwise, the IME will remain running and its + {@link android.inputmethodservice.InputMethodService#onConfigurationChanged} + method is called with the new configuration. + <p>Note that all of these configuration changes can impact the + resource values seen by the application, so you will generally need + to re-retrieve all resources (including view layouts, drawables, etc) + to correctly handle any configuration change.--> + <attr name="configChanges" /> </declare-styleable> <!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index cc52655ad7d2..601d66ec7b39 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -829,7 +829,6 @@ {@code FLAG_ACTIVITY_MULTIPLE_TASK} is set.--> <enum name="singleInstancePerTask" value="4" /> </attr> - <!-- Specify the orientation an activity should be run in. If not specified, it will run in the current preferred orientation of the screen. @@ -1603,6 +1602,12 @@ <enum name="sync" value="2" /> </attr> + <!-- Attribution tag to be used for permission sub-attribution if a + permission is checked in {@link android.content.Context#sendBroadcast(Intent, String)}. + Multiple tags can be specified separated by '|'. + --> + <attr name="attributionTags" format="string" /> + <!-- The <code>manifest</code> tag is the root of an <code>AndroidManifest.xml</code> file, describing the contents of an Android package (.apk) file. One @@ -2825,6 +2830,10 @@ <p> See {@link android.content.pm.ActivityInfo#FLAG_PREFER_MINIMAL_POST_PROCESSING} --> <attr name="preferMinimalPostProcessing" format="boolean"/> + <!-- Specify the attributionTags to be used if a permission is required due to + {@link android.content.Context#sendBroadcast(Intent, String)} being used. + Multiple tags can be specified separated by '|'. --> + <attr name="attributionTags"/> </declare-styleable> <!-- The <code>activity-alias</code> tag declares a new diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 8bc3a52fa17b..f6fee880bf2f 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -324,9 +324,6 @@ <item>"0,1"</item> </string-array> - <!-- The maximum duration (in milliseconds) we expect a network transition to take --> - <integer name="config_networkTransitionTimeout">60000</integer> - <!-- Whether/how to notify the user on network switches. See LingerMonitor.java. --> <integer translatable="false" name="config_networkNotifySwitchType">0</integer> @@ -339,16 +336,6 @@ Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. --> <integer translatable="false" name="config_networkAvoidBadWifi">1</integer> - <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl. - If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL, - and if that value is empty, the framework will use a hard-coded default. - This is *NOT* a URL that will always be used by the system network validation to detect - captive portals: NetworkMonitor may use different strategies and will not necessarily use - this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays - instead. --> - <!--suppress CheckTagEmptyBody --> - <string translatable="false" name="config_networkCaptivePortalServerUrl"></string> - <!-- If the hardware supports specially marking packets that caused a wakeup of the main CPU, set this value to the mark used. --> <integer name="config_networkWakeupPacketMark">0</integer> @@ -456,14 +443,6 @@ apps requested it. --> <bool name="config_vehicleInternalNetworkAlwaysRequested">false</bool> - <!-- Configuration of network interfaces that support WakeOnLAN --> - <string-array translatable="false" name="config_wakeonlan_supported_interfaces"> - <!-- - <item>wlan0</item> - <item>eth0</item> - --> - </string-array> - <!-- This setting is deprecated, please use com.android.networkstack.tethering.R.array.config_mobile_hotspot_provision_app instead. --> <string-array translatable="false" name="config_mobile_hotspot_provision_app"> @@ -1961,6 +1940,8 @@ <string name="config_systemWifiCoexManager" translateable="false"></string> <!-- The name of the package that will hold the wellbeing role. --> <string name="config_systemWellbeing" translatable="false"></string> + <!-- The name of the package that will hold the television notification handler role --> + <string name="config_systemTelevisionNotificationHandler" translatable="false"></string> <!-- The name of the package that will be allowed to change its components' label/icon. --> <string name="config_overrideComponentUiPackage" translatable="false"></string> @@ -2270,6 +2251,9 @@ <bool name="config_dozeWakeLockScreenSensorAvailable">false</bool> <integer name="config_dozeWakeLockScreenDebounce">300</integer> + <!-- Type of the quick pickup sensor. Empty if quick pickup is not supported. --> + <string name="config_quickPickupSensorType" translatable="false"></string> + <!-- Control whether the always on display mode is available. This should only be enabled on devices where the display has been tuned to be power efficient in DOZE and/or DOZE_SUSPEND states. --> @@ -4738,4 +4722,97 @@ <!-- Whether to allow the caching of the SIM PIN for verification after unattended reboot --> <bool name="config_allow_pin_storage_for_unattended_reboot">true</bool> + + <!-- CEC Configuration --> + <bool name="config_cecHdmiCecEnabled_userConfigurable">true</bool> + <bool name="config_cecHdmiCecControlEnabled_allowed">true</bool> + <bool name="config_cecHdmiCecControlEnabled_default">true</bool> + <bool name="config_cecHdmiCecControlDisabled_allowed">true</bool> + <bool name="config_cecHdmiCecControlDisabled_default">false</bool> + + <bool name="config_cecHdmiCecVersion_userConfigurable">true</bool> + <bool name="config_cecHdmiCecVersion14b_allowed">true</bool> + <bool name="config_cecHdmiCecVersion14b_default">true</bool> + <bool name="config_cecHdmiCecVersion20_allowed">true</bool> + <bool name="config_cecHdmiCecVersion20_default">false</bool> + + <bool name="config_cecSendStandbyOnSleep_userConfigurable">true</bool> + <bool name="config_cecPowerControlModeTv_allowed">true</bool> + <bool name="config_cecPowerControlModeTv_default">true</bool> + <bool name="config_cecPowerControlModeBroadcast_allowed">true</bool> + <bool name="config_cecPowerControlModeBroadcast_default">false</bool> + <bool name="config_cecPowerControlModeNone_allowed">true</bool> + <bool name="config_cecPowerControlModeNone_default">false</bool> + + <bool name="config_cecPowerStateChangeOnActiveSourceLost_userConfigurable">true</bool> + <bool name="config_cecPowerStateChangeOnActiveSourceLostNone_allowed">true</bool> + <bool name="config_cecPowerStateChangeOnActiveSourceLostNone_default">true</bool> + <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed">true</bool> + <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default">false</bool> + + <bool name="config_cecSystemAudioModeMuting_userConfigurable">true</bool> + <bool name="config_cecSystemAudioModeMutingEnabled_allowed">true</bool> + <bool name="config_cecSystemAudioModeMutingEnabled_default">true</bool> + <bool name="config_cecSystemAudioModeMutingDisabled_allowed">true</bool> + <bool name="config_cecSystemAudioModeMutingDisabled_default">false</bool> + + <bool name="config_cecVolumeControlMode_userConfigurable">true</bool> + <bool name="config_cecVolumeControlModeEnabled_allowed">true</bool> + <bool name="config_cecVolumeControlModeEnabled_default">true</bool> + <bool name="config_cecVolumeControlModeDisabled_allowed">true</bool> + <bool name="config_cecVolumeControlModeDisabled_default">false</bool> + + <bool name="config_cecTvWakeOnOneTouchPlay_userConfigurable">true</bool> + <bool name="config_cecTvWakeOnOneTouchPlayEnabled_allowed">true</bool> + <bool name="config_cecTvWakeOnOneTouchPlayEnabled_default">true</bool> + <bool name="config_cecTvWakeOnOneTouchPlayDisabled_allowed">true</bool> + <bool name="config_cecTvWakeOnOneTouchPlayDisabled_default">false</bool> + + <bool name="config_cecTvSendStandbyOnSleep_userConfigurable">true</bool> + <bool name="config_cecTvSendStandbyOnSleepEnabled_allowed">true</bool> + <bool name="config_cecTvSendStandbyOnSleepEnabled_default">true</bool> + <bool name="config_cecTvSendStandbyOnSleepDisabled_allowed">true</bool> + <bool name="config_cecTvSendStandbyOnSleepDisabled_default">false</bool> + + <bool name="config_cecRcProfileTv_userConfigurable">true</bool> + <bool name="config_cecRcProfileTvNone_allowed">true</bool> + <bool name="config_cecRcProfileTvNone_default">true</bool> + <bool name="config_cecRcProfileTvOne_allowed">true</bool> + <bool name="config_cecRcProfileTvOne_default">false</bool> + <bool name="config_cecRcProfileTvTwo_allowed">true</bool> + <bool name="config_cecRcProfileTvTwo_default">false</bool> + <bool name="config_cecRcProfileTvThree_allowed">true</bool> + <bool name="config_cecRcProfileTvThree_default">false</bool> + <bool name="config_cecRcProfileTvFour_allowed">true</bool> + <bool name="config_cecRcProfileTvFour_default">false</bool> + + <bool name="config_cecRcProfileSourceRootMenu_userConfigurable">true</bool> + <bool name="config_cecRcProfileSourceRootMenuHandled_allowed">true</bool> + <bool name="config_cecRcProfileSourceRootMenuHandled_default">true</bool> + <bool name="config_cecRcProfileSourceRootMenuNotHandled_allowed">true</bool> + <bool name="config_cecRcProfileSourceRootMenuNotHandled_default">false</bool> + + <bool name="config_cecRcProfileSourceSetupMenu_userConfigurable">true</bool> + <bool name="config_cecRcProfileSourceSetupMenuHandled_allowed">true</bool> + <bool name="config_cecRcProfileSourceSetupMenuHandled_default">true</bool> + <bool name="config_cecRcProfileSourceSetupMenuNotHandled_allowed">true</bool> + <bool name="config_cecRcProfileSourceSetupMenuNotHandled_default">false</bool> + + <bool name="config_cecRcProfileSourceContentsMenu_userConfigurable">true</bool> + <bool name="config_cecRcProfileSourceContentsMenuHandled_allowed">true</bool> + <bool name="config_cecRcProfileSourceContentsMenuHandled_default">false</bool> + <bool name="config_cecRcProfileSourceContentsMenuNotHandled_allowed">true</bool> + <bool name="config_cecRcProfileSourceContentsMenuNotHandled_default">true</bool> + + <bool name="config_cecRcProfileSourceTopMenu_userConfigurable">true</bool> + <bool name="config_cecRcProfileSourceTopMenuHandled_allowed">true</bool> + <bool name="config_cecRcProfileSourceTopMenuHandled_default">false</bool> + <bool name="config_cecRcProfileSourceTopMenuNotHandled_allowed">true</bool> + <bool name="config_cecRcProfileSourceTopMenuNotHandled_default">true</bool> + + <bool name="config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable">true</bool> + <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed">true</bool> + <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default">false</bool> + <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed">true</bool> + <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default">true</bool> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 10aa7b3f4354..43dbd38d1dc4 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -746,7 +746,7 @@ <dimen name="notification_right_icon_headerless_margin">20dp</dimen> <!-- The top margin of the right icon in the "big" notification states --> <!-- TODO(b/181048615): Move the large icon below the expander in big states --> - <dimen name="notification_right_icon_big_margin_top">20dp</dimen> + <dimen name="notification_right_icon_big_margin_top">16dp</dimen> <!-- The size of the left icon --> <dimen name="notification_left_icon_size">@dimen/notification_icon_circle_size</dimen> <!-- The left padding of the left icon --> diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index 3a41d5fed238..7bc4663d1070 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -247,4 +247,10 @@ <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_IME_ENTER}. --> <item type="id" name="accessibilityActionImeEnter" /> + + <!-- View tag for remote views to store the index of the next child when adding nested remote views dynamically. --> + <item type="id" name="remote_views_next_child" /> + + <!-- View tag associating a view with its stable id for potential recycling. --> + <item type="id" name = "remote_views_stable_id" /> </resources> diff --git a/core/res/res/values/policy_exempt_apps.xml b/core/res/res/values/policy_exempt_apps.xml new file mode 100644 index 000000000000..1cead8322e55 --- /dev/null +++ b/core/res/res/values/policy_exempt_apps.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<resources> + <!-- + A collection of apps that are critical for the device and hence will never be disabled by + device policies or APIs. + --> + <string-array translatable="false" name="policy_exempt_apps"> + </string-array> +</resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 293018d881d8..40c80dbeeb73 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3071,7 +3071,6 @@ <public name="windowSplashScreenAnimationDuration"/> <public name="windowSplashScreenBrandingImage"/> <public name="splashScreenTheme" /> - <public name="rippleStyle" /> <public name="maxResizeWidth" /> <public name="maxResizeHeight" /> <public name="targetCellWidth" /> @@ -3088,6 +3087,7 @@ <public name="passwordsActivity"/> <public name="selectableAsDefault"/> <public name="isAccessibilityTool"/> + <public name="attributionTags"/> </public-group> <public-group type="drawable" first-id="0x010800b5"> @@ -3175,6 +3175,8 @@ <public name="config_systemWifiCoexManager" /> <!-- @hide @SystemApi --> <public name="config_systemWellbeing" /> + <!-- @hide @SystemApi --> + <public name="config_systemTelevisionNotificationHandler" /> </public-group> <public-group type="id" first-id="0x01020055"> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 2ffa29b53331..387c065175be 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1532,6 +1532,8 @@ <string name="biometric_dialog_default_title">Verify it\u2019s you</string> <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face). [CHAR LIMIT=70] --> <string name="biometric_dialog_default_subtitle">Use your biometric to continue</string> + <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face) or their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=90] --> + <string name="biometric_or_screen_lock_dialog_default_subtitle">Use your biometric or screen lock to continue</string> <!-- Message shown when biometric hardware is not available [CHAR LIMIT=50] --> <string name="biometric_error_hw_unavailable">Biometric hardware unavailable</string> @@ -1604,6 +1606,8 @@ <string name="fingerprint_or_screen_lock_app_setting_name">Use fingerprint or screen lock</string> <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their fingerprint. [CHAR LIMIT=70] --> <string name="fingerprint_dialog_default_subtitle">Use your fingerprint to continue</string> + <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their fingerprint or screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=90] --> + <string name="fingerprint_or_screen_lock_dialog_default_subtitle">Use your fingerprint or screen lock to continue</string> <!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings --> <string-array name="fingerprint_error_vendor"> @@ -1704,6 +1708,8 @@ <string name="face_or_screen_lock_app_setting_name">Use face or screen lock</string> <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their face. [CHAR LIMIT=70] --> <string name="face_dialog_default_subtitle">Use face unlock to continue</string> + <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their face or screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=90] --> + <string name="face_or_screen_lock_dialog_default_subtitle">Use your face or screen lock to continue</string> <!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings --> <string-array name="face_error_vendor"> @@ -3685,6 +3691,8 @@ <string name="ext_media_checking_notification_title">Checking <xliff:g id="name" example="SD card">%s</xliff:g>\u2026</string> <!-- Notification body when external media is being checked [CHAR LIMIT=NONE] --> <string name="ext_media_checking_notification_message">Reviewing current content</string> + <!-- TV specific notification body when external media is being checked [CHAR LIMIT=75] --> + <string name="ext_media_checking_notification_message" product="tv">Analyzing media storage</string> <!-- Notification body when new external media is detected [CHAR LIMIT=30] --> <string name="ext_media_new_notification_title">New <xliff:g id="name" example="SD card">%s</xliff:g></string> @@ -3692,11 +3700,15 @@ <string name="ext_media_new_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string> <!-- Notification body when new external media is detected [CHAR LIMIT=NONE] --> <string name="ext_media_new_notification_message">Tap to set up</string> + <!-- TV specific notification body when new external media is detected [CHAR LIMIT=75] --> + <string name="ext_media_new_notification_message" product="tv">Select to set up</string> <!-- Automotive specific notification body when new external media is detected. [CHAR LIMIT=NONE] --> <string name="ext_media_new_notification_message" product="automotive">You may need to reformat the device. Tap to eject.</string> <!-- Notification body when external media is ready for use [CHAR LIMIT=NONE] --> <string name="ext_media_ready_notification_message">For transferring photos and media</string> + <!-- TV specific notification body when external media is ready for use [CHAR LIMIT=75] --> + <string name="ext_media_ready_notification_message" product="tv">Browse media files</string> <!-- Notification title when external media is unmountable (corrupt) [CHAR LIMIT=30] --> <string name="ext_media_unmountable_notification_title">Issue with <xliff:g id="name" example="SD card">%s</xliff:g></string> @@ -3715,8 +3727,8 @@ <string name="ext_media_unsupported_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string> <!-- Notification body when external media is unsupported [CHAR LIMIT=NONE] --> <string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Tap to set up in a supported format.</string> - <!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=NONE] --> - <string name="ext_media_unsupported_notification_message" product="tv">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Select to set up in a supported format.</string> + <!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=75] --> + <string name="ext_media_unsupported_notification_message" product="tv">Select to set up <xliff:g id="name" example="SD card">%s</xliff:g> in a supported format.</string> <!-- Automotive specific notification body when external media is unsupported [CHAR LIMIT=NONE] --> <string name="ext_media_unsupported_notification_message" product="automotive">You may need to reformat the device</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 07938fd3a324..5a7b1faf36b2 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -692,7 +692,6 @@ <java-symbol type="string" name="not_checked" /> <java-symbol type="array" name="config_ethernet_interfaces" /> <java-symbol type="bool" name="config_vehicleInternalNetworkAlwaysRequested" /> - <java-symbol type="array" name="config_wakeonlan_supported_interfaces" /> <java-symbol type="string" name="config_forceVoiceInteractionServicePackage" /> <java-symbol type="string" name="config_mms_user_agent" /> <java-symbol type="string" name="config_mms_user_agent_profile_url" /> @@ -1266,6 +1265,8 @@ <java-symbol type="array" name="vendor_disallowed_apps_managed_device" /> <java-symbol type="array" name="cross_profile_apps" /> <java-symbol type="array" name="vendor_cross_profile_apps" /> + <java-symbol type="array" name="policy_exempt_apps" /> + <java-symbol type="array" name="vendor_policy_exempt_apps" /> <java-symbol type="drawable" name="default_wallpaper" /> <java-symbol type="drawable" name="default_lock_wallpaper" /> @@ -1970,11 +1971,9 @@ <java-symbol type="integer" name="config_lowBatteryCloseWarningBump" /> <java-symbol type="integer" name="config_lowBatteryWarningLevel" /> <java-symbol type="integer" name="config_networkPolicyDefaultWarning" /> - <java-symbol type="integer" name="config_networkTransitionTimeout" /> <java-symbol type="integer" name="config_networkNotifySwitchType" /> <java-symbol type="array" name="config_networkNotifySwitches" /> <java-symbol type="integer" name="config_networkAvoidBadWifi" /> - <java-symbol type="string" name="config_networkCaptivePortalServerUrl" /> <java-symbol type="integer" name="config_networkWakeupPacketMark" /> <java-symbol type="integer" name="config_networkWakeupPacketMask" /> <java-symbol type="bool" name="config_apfDrop802_3Frames" /> @@ -2473,6 +2472,7 @@ <java-symbol type="string" name="biometric_or_screen_lock_app_setting_name" /> <java-symbol type="string" name="biometric_dialog_default_title" /> <java-symbol type="string" name="biometric_dialog_default_subtitle" /> + <java-symbol type="string" name="biometric_or_screen_lock_dialog_default_subtitle" /> <java-symbol type="string" name="biometric_error_hw_unavailable" /> <java-symbol type="string" name="biometric_error_user_canceled" /> <java-symbol type="string" name="biometric_not_recognized" /> @@ -2504,6 +2504,7 @@ <java-symbol type="string" name="fingerprint_app_setting_name" /> <java-symbol type="string" name="fingerprint_or_screen_lock_app_setting_name" /> <java-symbol type="string" name="fingerprint_dialog_default_subtitle" /> + <java-symbol type="string" name="fingerprint_or_screen_lock_dialog_default_subtitle" /> <java-symbol type="string" name="fingerprint_authenticated" /> <java-symbol type="string" name="fingerprint_error_no_fingerprints" /> <java-symbol type="string" name="fingerprint_error_hw_not_present" /> @@ -2553,6 +2554,7 @@ <java-symbol type="string" name="face_app_setting_name" /> <java-symbol type="string" name="face_or_screen_lock_app_setting_name" /> <java-symbol type="string" name="face_dialog_default_subtitle" /> + <java-symbol type="string" name="face_or_screen_lock_dialog_default_subtitle" /> <java-symbol type="string" name="face_authenticated_no_confirmation_required" /> <java-symbol type="string" name="face_authenticated_confirmation_required" /> <java-symbol type="string" name="face_error_security_update_required" /> @@ -3592,6 +3594,7 @@ <java-symbol type="string" name="config_dozeUdfpsLongPressSensorType" /> <java-symbol type="bool" name="config_dozeWakeLockScreenSensorAvailable" /> <java-symbol type="integer" name="config_dozeWakeLockScreenDebounce" /> + <java-symbol type="string" name="config_quickPickupSensorType" /> <java-symbol type="array" name="config_allowedGlobalInstantAppSettings" /> <java-symbol type="array" name="config_allowedSystemInstantAppSettings" /> @@ -4221,4 +4224,100 @@ <java-symbol type="bool" name="config_voice_data_sms_auto_fallback" /> <java-symbol type="bool" name="config_enableOneHandedKeyguard" /> + + <!-- CEC Configuration --> + <java-symbol type="bool" name="config_cecHdmiCecEnabled_userConfigurable" /> + <java-symbol type="bool" name="config_cecHdmiCecControlEnabled_allowed" /> + <java-symbol type="bool" name="config_cecHdmiCecControlEnabled_default" /> + <java-symbol type="bool" name="config_cecHdmiCecControlDisabled_allowed" /> + <java-symbol type="bool" name="config_cecHdmiCecControlDisabled_default" /> + + <java-symbol type="bool" name="config_cecHdmiCecVersion_userConfigurable" /> + <java-symbol type="bool" name="config_cecHdmiCecVersion14b_allowed" /> + <java-symbol type="bool" name="config_cecHdmiCecVersion14b_default" /> + <java-symbol type="bool" name="config_cecHdmiCecVersion20_allowed" /> + <java-symbol type="bool" name="config_cecHdmiCecVersion20_default" /> + + <java-symbol type="bool" name="config_cecSendStandbyOnSleep_userConfigurable" /> + <java-symbol type="bool" name="config_cecPowerControlModeTv_allowed" /> + <java-symbol type="bool" name="config_cecPowerControlModeTv_default" /> + <java-symbol type="bool" name="config_cecPowerControlModeBroadcast_allowed" /> + <java-symbol type="bool" name="config_cecPowerControlModeBroadcast_default" /> + <java-symbol type="bool" name="config_cecPowerControlModeNone_allowed" /> + <java-symbol type="bool" name="config_cecPowerControlModeNone_default" /> + + <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLost_userConfigurable" /> + <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostNone_allowed" /> + <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostNone_default" /> + <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed" /> + <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default" /> + + <java-symbol type="bool" name="config_cecSystemAudioModeMuting_userConfigurable" /> + <java-symbol type="bool" name="config_cecSystemAudioModeMutingEnabled_allowed" /> + <java-symbol type="bool" name="config_cecSystemAudioModeMutingEnabled_default" /> + <java-symbol type="bool" name="config_cecSystemAudioModeMutingDisabled_allowed" /> + <java-symbol type="bool" name="config_cecSystemAudioModeMutingDisabled_default" /> + + <java-symbol type="bool" name="config_cecVolumeControlMode_userConfigurable" /> + <java-symbol type="bool" name="config_cecVolumeControlModeEnabled_allowed" /> + <java-symbol type="bool" name="config_cecVolumeControlModeEnabled_default" /> + <java-symbol type="bool" name="config_cecVolumeControlModeDisabled_allowed" /> + <java-symbol type="bool" name="config_cecVolumeControlModeDisabled_default" /> + + <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlay_userConfigurable" /> + <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayEnabled_allowed" /> + <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayEnabled_default" /> + <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayDisabled_allowed" /> + <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayDisabled_default" /> + + <java-symbol type="bool" name="config_cecTvSendStandbyOnSleep_userConfigurable" /> + <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepEnabled_allowed" /> + <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepEnabled_default" /> + <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_allowed" /> + <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_default" /> + + <java-symbol type="bool" name="config_cecRcProfileTv_userConfigurable" /> + <java-symbol type="bool" name="config_cecRcProfileTvNone_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileTvNone_default" /> + <java-symbol type="bool" name="config_cecRcProfileTvOne_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileTvOne_default" /> + <java-symbol type="bool" name="config_cecRcProfileTvTwo_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileTvTwo_default" /> + <java-symbol type="bool" name="config_cecRcProfileTvThree_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileTvThree_default" /> + <java-symbol type="bool" name="config_cecRcProfileTvFour_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileTvFour_default" /> + + <java-symbol type="bool" name="config_cecRcProfileSourceRootMenu_userConfigurable" /> + <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuHandled_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuHandled_default" /> + <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuNotHandled_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuNotHandled_default" /> + + <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenu_userConfigurable" /> + <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuHandled_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuHandled_default" /> + <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuNotHandled_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuNotHandled_default" /> + + <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenu_userConfigurable" /> + <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuHandled_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuHandled_default" /> + <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuNotHandled_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuNotHandled_default" /> + + <java-symbol type="bool" name="config_cecRcProfileSourceTopMenu_userConfigurable" /> + <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuHandled_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuHandled_default" /> + <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuNotHandled_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuNotHandled_default" /> + + <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable" /> + <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default" /> + <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed" /> + <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default" /> + + <java-symbol type="id" name="remote_views_next_child" /> + <java-symbol type="id" name="remote_views_stable_id" /> </resources> diff --git a/core/res/res/values/vendor_policy_exempt_apps.xml b/core/res/res/values/vendor_policy_exempt_apps.xml new file mode 100644 index 000000000000..eb4c760b6724 --- /dev/null +++ b/core/res/res/values/vendor_policy_exempt_apps.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<resources> + <!-- + A collection of apps that are critical for the device and hence will never be disabled by + device policies or APIs. + --> + <string-array translatable="false" name="vendor_policy_exempt_apps"> + </string-array> +</resources> diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java new file mode 100644 index 000000000000..fe31b907f077 --- /dev/null +++ b/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.appsearch; + +import static com.google.common.truth.Truth.assertThat; + +import static org.testng.Assert.expectThrows; + +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; + +public class AppSearchSessionUnitTest { + private final Context mContext = ApplicationProvider.getApplicationContext(); + private final AppSearchManager mAppSearch = mContext.getSystemService(AppSearchManager.class); + private final Executor mExecutor = mContext.getMainExecutor(); + private AppSearchSession mSearchSession; + + @Before + public void setUp() throws Exception { + // Remove all documents from any instances that may have been created in the tests. + Objects.requireNonNull(mAppSearch); + AppSearchManager.SearchContext searchContext = new AppSearchManager.SearchContext.Builder() + .setDatabaseName("testDb").build(); + CompletableFuture<AppSearchResult<AppSearchSession>> future = new CompletableFuture<>(); + mAppSearch.createSearchSession(searchContext, mExecutor, future::complete); + mSearchSession = future.get().getResultValue(); + + CompletableFuture<AppSearchResult<SetSchemaResponse>> schemaFuture = + new CompletableFuture<>(); + mSearchSession.setSchema( + new SetSchemaRequest.Builder().setForceOverride(true).build(), mExecutor, + schemaFuture::complete); + + schemaFuture.get().getResultValue(); + } + + @Test + public void testPutDocument_throwsNullException() throws Exception { + // Create a document + AppSearchEmail inEmail = + new AppSearchEmail.Builder("uri1") + .setFrom("from@example.com") + .setTo("to1@example.com", "to2@example.com") + .setSubject("testPut example") + .setBody("This is the body of the testPut email") + .build(); + + // clear the document bundle to make our service crash and throw an NullPointerException. + inEmail.getBundle().clear(); + CompletableFuture<AppSearchBatchResult<String, Void>> putDocumentsFuture = + new CompletableFuture<>(); + + // Index the broken document. + mSearchSession.put( + new PutDocumentsRequest.Builder().addGenericDocuments(inEmail).build(), + mExecutor, new BatchResultCallback<String, Void>() { + @Override + public void onResult(AppSearchBatchResult<String, Void> result) { + putDocumentsFuture.complete(result); + } + + @Override + public void onSystemError(Throwable throwable) { + putDocumentsFuture.completeExceptionally(throwable); + } + }); + + // Verify the NullPointException has been thrown. + ExecutionException executionException = expectThrows(ExecutionException.class, + putDocumentsFuture::get); + assertThat(executionException.getCause()).isInstanceOf(NullPointerException.class); + } +} diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index 57c0be5007b8..5d75d9b3f70b 100644 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -2923,7 +2923,7 @@ public class PackageManagerTests extends AndroidTestCase { assertFalse("BaseCodePath should not be registered", callback.mSuccess); } - // Verify thatmodules which are not own by the calling package are not registered. + // Verify that modules which are not own by the calling package are not registered. public void testRegisterDexModuleNotOwningModule() throws Exception { TestDexModuleRegisterCallback callback = new TestDexModuleRegisterCallback(); String moduleBelongingToOtherPackage = "/data/user/0/com.google.android.gms/module.apk"; @@ -2978,6 +2978,13 @@ public class PackageManagerTests extends AndroidTestCase { assertFalse("DexModule registration should fail", callback.mSuccess); } + // If the module does not exist on disk we should get a failure. + public void testRegisterDexModuleNotExistsNoCallback() throws Exception { + ApplicationInfo info = getContext().getApplicationInfo(); + String nonExistentApk = Paths.get(info.dataDir, "non-existent.apk").toString(); + getPm().registerDexModule(nonExistentApk, null); + } + // Copied from com.android.server.pm.InstructionSets because we don't have access to it here. private static String[] getAppDexInstructionSets(ApplicationInfo info) { if (info.primaryCpuAbi != null) { diff --git a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java b/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java new file mode 100644 index 000000000000..4863cfe588ba --- /dev/null +++ b/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.inputmethodservice; + +import static android.content.res.Configuration.KEYBOARD_12KEY; +import static android.content.res.Configuration.NAVIGATION_NONAV; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + + +import static junit.framework.Assert.assertFalse; + +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.os.Build; + +import androidx.test.filters.SmallTest; +import androidx.test.rule.ServiceTestRule; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.TimeoutException; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class InputMethodServiceTest { + private InputMethodService mService; + private Context mContext; + @Rule + public final ServiceTestRule serviceRule = new ServiceTestRule(); + + @Before + public void setUp() throws TimeoutException { + mContext = getInstrumentation().getContext(); + mService = new InputMethodService(); + } + + @Test + public void testShouldImeRestartForConfig() throws Exception { + // Make sure we preserve Pre-S behavior i.e. Service restarts. + mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R; + Configuration config = mContext.getResources().getConfiguration(); + mService.setLastKnownConfig(config); + assertTrue("IME should restart for Pre-S", + mService.shouldImeRestartForConfig(config)); + + // IME shouldn't restart on targetSdk S+ (with no config changes). + mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.S; + assertFalse("IME shouldn't restart for S+", + mService.shouldImeRestartForConfig(config)); + + // Screen density changed but IME doesn't handle congfigChanges + config.densityDpi = 99; + assertTrue("IME should restart for unhandled configChanges", + mService.shouldImeRestartForConfig(config)); + + // opt-in IME to handle config changes. + mService.setHandledConfigChanges(ActivityInfo.CONFIG_DENSITY); + assertFalse("IME shouldn't restart for S+ since it handles configChanges", + mService.shouldImeRestartForConfig(config)); + } +} diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS index 80165f065995..fa1aa5eab26c 100644 --- a/core/tests/coretests/src/android/view/OWNERS +++ b/core/tests/coretests/src/android/view/OWNERS @@ -9,3 +9,6 @@ per-file *Focus* = file:/services/core/java/com/android/server/wm/OWNERS per-file *Insets* = file:/services/core/java/com/android/server/wm/OWNERS per-file *View* = file:/services/core/java/com/android/server/wm/OWNERS per-file *Visibility* = file:/services/core/java/com/android/server/wm/OWNERS + +# Scroll Capture +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java index 1e0e1235161c..f5fcb03bb816 100644 --- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java +++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java @@ -125,7 +125,7 @@ public class InputMethodSubtypeTest { assertEquals("he", clonedSubtypeHe.getLocale()); } - private static final InputMethodSubtype cloneViaParcel(final InputMethodSubtype original) { + private static InputMethodSubtype cloneViaParcel(final InputMethodSubtype original) { Parcel parcel = null; try { parcel = Parcel.obtain(); @@ -157,4 +157,4 @@ public class InputMethodSubtypeTest { .setIsAsciiCapable(true) .build(); } -}
\ No newline at end of file +} diff --git a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java index 453ad72b64dc..f264cc630dc5 100644 --- a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java +++ b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java @@ -62,20 +62,20 @@ public class SparseRectFArrayTest { @Test public void testBuilder() throws Exception { - final RectF TEMP_RECT = new RectF(10.0f, 20.0f, 30.0f, 40.0f); - final int TEMP_FLAGS = 0x1234; + final RectF testRect = new RectF(10.0f, 20.0f, 30.0f, 40.0f); + final int testFlags = 0x1234; final SparseRectFArrayBuilder builder = new SparseRectFArrayBuilder(); - builder.append(100, TEMP_RECT.left, TEMP_RECT.top, TEMP_RECT.right, TEMP_RECT.bottom, - TEMP_FLAGS); + builder.append(100, testRect.left, testRect.top, testRect.right, testRect.bottom, + testFlags); assertNull(builder.build().get(-1)); assertNull(builder.build().get(0)); assertNull(builder.build().get(99)); assertEquals(0, builder.build().getFlags(99, 0 /* valueIfKeyNotFound */)); assertEquals(1, builder.build().getFlags(99, 1 /* valueIfKeyNotFound */)); - assertEquals(TEMP_RECT, builder.build().get(100)); - assertEquals(TEMP_FLAGS, builder.build().getFlags(100, 0 /* valueIfKeyNotFound */)); - assertEquals(TEMP_FLAGS, builder.build().getFlags(100, 1 /* valueIfKeyNotFound */)); + assertEquals(testRect, builder.build().get(100)); + assertEquals(testFlags, builder.build().getFlags(100, 0 /* valueIfKeyNotFound */)); + assertEquals(testFlags, builder.build().getFlags(100, 1 /* valueIfKeyNotFound */)); assertNull(builder.build().get(101)); assertEquals(0, builder.build().getFlags(101, 0 /* valueIfKeyNotFound */)); assertEquals(1, builder.build().getFlags(101, 1 /* valueIfKeyNotFound */)); diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java index f6e02bc1f48a..28f9ccc10135 100644 --- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java +++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java @@ -41,7 +41,9 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import android.content.res.TypedArray; import android.text.Selection; @@ -356,4 +358,71 @@ public class SuggestionsPopupWindowTest { .perform(clearText()); } } + + @Test + public void testCursorVisibility() { + final TextView textView = getActivity().findViewById(R.id.textview); + final String text = "abc"; + + assertTrue(textView.isCursorVisible()); + + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(replaceText(text)); + final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(), + new String[]{"ABC"}, SuggestionSpan.FLAG_AUTO_CORRECTION); + setSuggestionSpan(suggestionSpan, text.indexOf('a'), text.indexOf('c') + 1); + showSuggestionsPopup(); + + assertSuggestionsPopupIsDisplayed(); + assertSuggestionsPopupContainsItem("ABC"); + assertFalse(textView.isCursorVisible()); + + // Delete an item. + clickSuggestionsPopupItem( + getActivity().getString(com.android.internal.R.string.delete)); + assertSuggestionsPopupIsNotDisplayed(); + assertTrue(textView.isCursorVisible()); + } + + @Test + public void testCursorVisibilityWhenImeConsumesInput() { + final TextView textView = getActivity().findViewById(R.id.textview); + final String text = "abc"; + + assertTrue(textView.isCursorVisible()); + + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(replaceText(text)); + setImeConsumesInputWithExpect(textView, true /* imeConsumesInput */, + false /* expectedCursorVisibility */); + final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(), + new String[]{"ABC"}, SuggestionSpan.FLAG_AUTO_CORRECTION); + setSuggestionSpan(suggestionSpan, text.indexOf('a'), text.indexOf('c') + 1); + showSuggestionsPopup(); + + assertSuggestionsPopupIsDisplayed(); + assertSuggestionsPopupContainsItem("ABC"); + assertFalse(textView.isCursorVisible()); + + // Delete an item. + clickSuggestionsPopupItem( + getActivity().getString(com.android.internal.R.string.delete)); + assertSuggestionsPopupIsNotDisplayed(); + assertFalse(textView.isCursorVisible()); + + // Set IME not consumes input, cursor should be back to visible. + setImeConsumesInputWithExpect(textView, false /* imeConsumesInput */, + true /* expectedCursorVisibility */); + } + + private void setImeConsumesInputWithExpect( + final TextView textView, boolean imeConsumesInput, boolean expectedCursorVisibility) { + textView.post(() -> textView.setImeConsumesInput(imeConsumesInput)); + getInstrumentation().waitForIdleSync(); + if (expectedCursorVisibility) { + assertTrue(textView.isCursorVisible()); + } else { + assertFalse(textView.isCursorVisible()); + } + } } diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java index d50bb05c3588..b89e8bce5fc9 100644 --- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java @@ -232,7 +232,7 @@ public final class LooperStatsTest { assertThat(entry3.handlerClassName).isEqualTo( "com.android.internal.os.LooperStatsTest$TestHandlerSecond"); assertThat(entry3.messageName).startsWith( - "com.android.internal.os.LooperStatsTest-$$ExternalSyntheticLambda"); + "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda4"); assertThat(entry3.messageCount).isEqualTo(1); assertThat(entry3.recordedMessageCount).isEqualTo(1); assertThat(entry3.exceptionCount).isEqualTo(0); diff --git a/core/tests/coretests/src/com/android/internal/view/OWNERS b/core/tests/coretests/src/com/android/internal/view/OWNERS new file mode 100644 index 000000000000..1dad10de5ac7 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/view/OWNERS @@ -0,0 +1,3 @@ +# Scroll Capture +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS +per-file *CaptureHelper*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/core/tests/mockingcoretests/src/android/view/DisplayTests.java b/core/tests/mockingcoretests/src/android/view/DisplayTests.java new file mode 100644 index 000000000000..a036db224a54 --- /dev/null +++ b/core/tests/mockingcoretests/src/android/view/DisplayTests.java @@ -0,0 +1,592 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Surface.ROTATION_0; +import static android.view.Surface.ROTATION_90; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Point; +import android.graphics.Rect; +import android.hardware.display.DisplayManagerGlobal; +import android.platform.test.annotations.Presubmit; +import android.util.DisplayMetrics; +import android.view.DisplayAdjustments.FixedRotationAdjustments; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.dx.mockito.inline.extended.StaticMockitoSession; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.quality.Strictness; + +import java.util.function.Consumer; + +/** + * Tests for {@link Display}. + * + * <p>Build/Install/Run: + * + * atest FrameworksMockingCoreTests:android.view.DisplayTests + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class DisplayTests { + + private static final int APP_WIDTH = 272; + private static final int APP_HEIGHT = 700; + // Tablet size device, ROTATION_0 corresponds to portrait. + private static final int LOGICAL_WIDTH = 700; + private static final int LOGICAL_HEIGHT = 1800; + + // Bounds of the app when the device is in portrait mode. + private static Rect sAppBoundsPortrait = buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT); + private static Rect sAppBoundsLandscape = buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH); + + // Bounds of the device. + private static Rect sDeviceBoundsPortrait = new Rect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT); + private static Rect sDeviceBoundsLandscape = new Rect(0, 0, LOGICAL_HEIGHT, LOGICAL_WIDTH); + + + private StaticMockitoSession mMockitoSession; + + private DisplayManagerGlobal mDisplayManagerGlobal; + private Context mApplicationContext; + private DisplayInfo mDisplayInfo = new DisplayInfo(); + + @Before + public void setupTests() { + mMockitoSession = mockitoSession() + .mockStatic(DisplayManagerGlobal.class) + .strictness(Strictness.LENIENT) + .startMocking(); + + // Ensure no adjustments are set before each test. + mApplicationContext = ApplicationProvider.getApplicationContext(); + DisplayAdjustments displayAdjustments = + mApplicationContext.getResources().getDisplayAdjustments(); + displayAdjustments.setFixedRotationAdjustments(null); + mApplicationContext.getResources().overrideDisplayAdjustments(null); + mApplicationContext.getResources().getConfiguration().windowConfiguration.setAppBounds( + null); + mApplicationContext.getResources().getConfiguration().windowConfiguration.setMaxBounds( + null); + mDisplayInfo.rotation = ROTATION_0; + + mDisplayManagerGlobal = mock(DisplayManagerGlobal.class); + doReturn(mDisplayInfo).when(mDisplayManagerGlobal).getDisplayInfo(anyInt()); + } + + @After + public void teardownTests() { + if (mMockitoSession != null) { + mMockitoSession.finishMocking(); + } + Mockito.framework().clearInlineMocks(); + } + + @Test + public void testConstructor_defaultDisplayAdjustments_matchesDisplayInfo() { + setDisplayInfoPortrait(mDisplayInfo); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); + assertThat(display.getDisplayAdjustments()).isEqualTo( + DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); + DisplayInfo actualDisplayInfo = new DisplayInfo(); + display.getDisplayInfo(actualDisplayInfo); + verifyDisplayInfo(actualDisplayInfo, mDisplayInfo); + } + + @Test + public void testConstructor_defaultResources_matchesDisplayInfo() { + setDisplayInfoPortrait(mDisplayInfo); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + assertThat(display.getDisplayAdjustments()).isEqualTo( + mApplicationContext.getResources().getDisplayAdjustments()); + DisplayInfo actualDisplayInfo = new DisplayInfo(); + display.getDisplayInfo(actualDisplayInfo); + verifyDisplayInfo(actualDisplayInfo, mDisplayInfo); + } + + @Test + public void testGetRotation_defaultDisplayAdjustments_rotationNotAdjusted() { + setDisplayInfoPortrait(mDisplayInfo); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); + assertThat(display.getRotation()).isEqualTo(ROTATION_0); + } + + @Test + public void testGetRotation_displayAdjustmentsWithoutOverride_rotationNotAdjusted() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + // GIVEN fixed rotation adjustments are rotated, but no override is set. + DisplayAdjustments displayAdjustments = DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; + final FixedRotationAdjustments fixedRotationAdjustments = + new FixedRotationAdjustments(ROTATION_90, APP_WIDTH, APP_HEIGHT, + DisplayCutout.NO_CUTOUT); + displayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments); + // GIVEN display is constructed with display adjustments. + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + displayAdjustments); + // THEN rotation is not adjusted since no override was set. + assertThat(display.getRotation()).isEqualTo(ROTATION_0); + } + + @Test + public void testGetRotation_resourcesWithoutOverride_rotationNotAdjusted() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + // GIVEN fixed rotation adjustments are rotated, but no override is set. + setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90); + // GIVEN display is constructed with default resources. + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN rotation is not adjusted since no override is set. + assertThat(display.getRotation()).isEqualTo(ROTATION_0); + } + + @Test + public void testGetRotation_resourcesWithOverrideDisplayAdjustments_rotationAdjusted() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + // GIVEN fixed rotation adjustments are rotated, and an override is set. + setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90); + // GIVEN display is constructed with default resources. + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN rotation is adjusted since an override is set. + assertThat(display.getRotation()).isEqualTo(ROTATION_90); + } + + @Test + public void testGetRealSize_defaultResourcesPortrait_matchesLogicalSize() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real size matches display orientation. + verifyRealSizeIsPortrait(display); + } + + @Test + public void testGetRealSize_defaultResourcesLandscape_matchesRotatedLogicalSize() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real size matches display orientation. + verifyRealSizeIsLandscape(display); + } + + @Test + public void testGetRealSize_defaultDisplayAdjustmentsPortrait_matchesLogicalSize() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); + // THEN real size matches display orientation. + verifyRealSizeIsPortrait(display); + } + + @Test + public void testGetRealSize_defaultDisplayAdjustmentsLandscape_matchesLogicalSize() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); + // THEN real size matches display orientation. + verifyRealSizeIsLandscape(display); + } + + @Test + public void testGetRealSize_resourcesPortraitWithFixedRotation_notRotatedLogicalSize() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + // GIVEN fixed rotation adjustments are rotated. + setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0); + // GIVEN display is constructed with default resources. + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real size matches display orientation. + verifyRealSizeIsLandscape(display); + } + + @Test + public void testGetRealSize_resourcesWithLandscapeFixedRotation_notRotatedLogicalSize() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + // GIVEN fixed rotation adjustments are rotated. + setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90); + // GIVEN display is constructed with default resources. + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real size matches display orientation. + verifyRealSizeIsPortrait(display); + } + + @Test + public void testGetRealSize_resourcesWithPortraitOverrideRotation_rotatedLogicalSize() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + // GIVEN fixed rotation adjustments are rotated, and an override is set. + setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0); + // GIVEN display is constructed with default resources. + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real size matches app orientation. + verifyRealSizeIsPortrait(display); + } + + @Test + public void testGetRealSize_resourcesWithLandscapeOverrideRotation_rotatedLogicalSize() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + // GIVEN fixed rotation adjustments are rotated, and an override is set. + setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90); + // GIVEN display is constructed with default resources. + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real size matches app orientation. + verifyRealSizeIsLandscape(display); + } + + @Test + public void testGetRealSize_resourcesPortraitSandboxed_matchesAppSandboxBounds() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + // GIVEN app is letterboxed. + setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsPortrait); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real size matches app bounds. + verifyRealSizeMatchesBounds(display, sAppBoundsPortrait); + } + + @Test + public void testGetRealSize_resourcesPortraitSandboxed_matchesDisplayAreaSandboxBounds() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + // GIVEN max bounds reflect DisplayArea size, which is the same size as the display. + setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsPortrait); + // GIVEN app bounds do not stretch to include the full DisplayArea. + mApplicationContext.getResources().getConfiguration().windowConfiguration + .setAppBounds(buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT - 10)); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches max bounds for the DisplayArea. + verifyRealSizeMatchesBounds(display, sDeviceBoundsPortrait); + } + + @Test + public void testGetRealSize_resourcesLandscapeSandboxed_matchesAppSandboxBounds() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + // GIVEN app is letterboxed. + setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsLandscape); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real size matches app bounds. + verifyRealSizeMatchesBounds(display, sAppBoundsLandscape); + } + + @Test + public void testGetRealSize_resourcesLandscapeSandboxed_matchesDisplayAreaSandboxBounds() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + // GIVEN max bounds reflect DisplayArea size, which is the same size as the display. + setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsLandscape); + // GIVEN app bounds do not stretch to include the full DisplayArea. + mApplicationContext.getResources().getConfiguration().windowConfiguration + .setAppBounds(buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH - 10)); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches max bounds for the DisplayArea. + verifyRealSizeMatchesBounds(display, sDeviceBoundsLandscape); + } + + @Test + public void testGetRealMetrics_defaultResourcesPortrait_matchesLogicalSize() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches display orientation. + verifyRealMetricsIsPortrait(display); + } + + @Test + public void testGetRealMetrics_defaultResourcesLandscape_matchesRotatedLogicalSize() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches display orientation. + verifyRealMetricsIsLandscape(display); + } + + @Test + public void testGetRealMetrics_defaultDisplayAdjustmentsPortrait_matchesLogicalSize() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); + // THEN real metrics matches display orientation. + verifyRealMetricsIsPortrait(display); + } + + @Test + public void testGetRealMetrics_defaultDisplayAdjustmentsLandscape_matchesLogicalSize() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); + // THEN real metrics matches display orientation. + verifyRealMetricsIsLandscape(display); + } + + @Test + public void testGetRealMetrics_resourcesPortraitWithFixedRotation_notRotatedLogicalSize() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + // GIVEN fixed rotation adjustments are rotated. + setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0); + // GIVEN display is constructed with default resources. + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches display orientation. + verifyRealMetricsIsLandscape(display); + } + + @Test + public void testGetRealMetrics_resourcesWithLandscapeFixedRotation_notRotatedLogicalSize() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + // GIVEN fixed rotation adjustments are rotated. + setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90); + // GIVEN display is constructed with default resources. + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches display orientation. + verifyRealMetricsIsPortrait(display); + } + + @Test + public void testGetRealMetrics_resourcesWithPortraitOverrideRotation_rotatedLogicalSize() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + // GIVEN fixed rotation adjustments are rotated with an override. + setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0); + // GIVEN display is constructed with default resources. + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches app orientation. + verifyRealMetricsIsPortrait(display); + } + + @Test + public void testGetRealMetrics_resourcesWithLandscapeOverrideRotation_rotatedLogicalSize() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + // GIVEN fixed rotation adjustments are rotated. + setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90); + // GIVEN display is constructed with default resources. + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches app orientation. + verifyRealMetricsIsLandscape(display); + } + + @Test + public void testGetRealMetrics_resourcesPortraitSandboxed_matchesAppSandboxBounds() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + // GIVEN app is letterboxed. + setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsPortrait); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches app bounds. + verifyRealMetricsMatchesBounds(display, sAppBoundsPortrait); + } + + @Test + public void testGetRealMetrics_resourcesPortraitSandboxed_matchesDisplayAreaSandboxBounds() { + // GIVEN display is not rotated. + setDisplayInfoPortrait(mDisplayInfo); + // GIVEN max bounds reflect DisplayArea size, which is the same size as the display. + setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsPortrait); + // GIVEN app bounds do not stretch to include the full DisplayArea. + mApplicationContext.getResources().getConfiguration().windowConfiguration + .setAppBounds(buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT - 10)); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches max bounds for the DisplayArea. + verifyRealMetricsMatchesBounds(display, sDeviceBoundsPortrait); + } + + @Test + public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesAppSandboxBounds() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + // GIVEN app is letterboxed. + setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsLandscape); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches app bounds. + verifyRealMetricsMatchesBounds(display, sAppBoundsLandscape); + } + + @Test + public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesDisplayAreaSandboxBounds() { + // GIVEN display is rotated. + setDisplayInfoLandscape(mDisplayInfo); + // GIVEN max bounds reflect DisplayArea size, which is the same size as the display. + setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsLandscape); + // GIVEN app bounds do not stretch to include the full DisplayArea. + mApplicationContext.getResources().getConfiguration().windowConfiguration + .setAppBounds(buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH - 10)); + final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo, + mApplicationContext.getResources()); + // THEN real metrics matches max bounds for the DisplayArea. + verifyRealMetricsMatchesBounds(display, sDeviceBoundsLandscape); + } + + // Given rotated display dimensions, calculate the letterboxed app bounds. + private static Rect buildAppBounds(int displayWidth, int displayHeight) { + final int midWidth = displayWidth / 2; + final int left = midWidth - (APP_WIDTH / 2); + final int right = midWidth + (APP_WIDTH / 2); + final int midHeight = displayHeight / 2; + // Coordinate system starts at top left. + final int top = midHeight - (APP_HEIGHT / 2); + final int bottom = midHeight + (APP_HEIGHT / 2); + return new Rect(left, top, right, bottom); + } + + private static void setDisplayInfoLandscape(DisplayInfo displayInfo) { + displayInfo.rotation = ROTATION_90; + // Flip width & height assignment since the device is rotated. + displayInfo.logicalWidth = LOGICAL_HEIGHT; + displayInfo.logicalHeight = LOGICAL_WIDTH; + } + + private static void setDisplayInfoPortrait(DisplayInfo displayInfo) { + displayInfo.rotation = ROTATION_0; + displayInfo.logicalWidth = LOGICAL_WIDTH; + displayInfo.logicalHeight = LOGICAL_HEIGHT; + } + + /** + * Set max bounds to be sandboxed to the app bounds, indicating the app is in + * size compat mode or letterbox. + */ + private static void setMaxBoundsSandboxed(Resources resources, Rect bounds) { + resources.getConfiguration().windowConfiguration.setMaxBounds(bounds); + } + + /** + * Do not compare entire display info, since it is updated to match display the test is run on. + */ + private static void verifyDisplayInfo(DisplayInfo actual, DisplayInfo expected) { + assertThat(actual.displayId).isEqualTo(expected.displayId); + assertThat(actual.rotation).isEqualTo(expected.rotation); + assertThat(actual.logicalWidth).isEqualTo(LOGICAL_WIDTH); + assertThat(actual.logicalHeight).isEqualTo(LOGICAL_HEIGHT); + } + + private static void verifyRealSizeIsLandscape(Display display) { + Point size = new Point(); + display.getRealSize(size); + // Flip the width and height check since the device is rotated. + assertThat(size).isEqualTo(new Point(LOGICAL_HEIGHT, LOGICAL_WIDTH)); + } + + private static void verifyRealMetricsIsLandscape(Display display) { + DisplayMetrics metrics = new DisplayMetrics(); + display.getRealMetrics(metrics); + // Flip the width and height check since the device is rotated. + assertThat(metrics.widthPixels).isEqualTo(LOGICAL_HEIGHT); + assertThat(metrics.heightPixels).isEqualTo(LOGICAL_WIDTH); + } + + private static void verifyRealSizeIsPortrait(Display display) { + Point size = new Point(); + display.getRealSize(size); + assertThat(size).isEqualTo(new Point(LOGICAL_WIDTH, LOGICAL_HEIGHT)); + } + + private static void verifyRealMetricsIsPortrait(Display display) { + DisplayMetrics metrics = new DisplayMetrics(); + display.getRealMetrics(metrics); + assertThat(metrics.widthPixels).isEqualTo(LOGICAL_WIDTH); + assertThat(metrics.heightPixels).isEqualTo(LOGICAL_HEIGHT); + } + + private static void verifyRealSizeMatchesBounds(Display display, Rect bounds) { + Point size = new Point(); + display.getRealSize(size); + assertThat(size).isEqualTo(new Point(bounds.width(), bounds.height())); + } + + private static void verifyRealMetricsMatchesBounds(Display display, Rect bounds) { + DisplayMetrics metrics = new DisplayMetrics(); + display.getRealMetrics(metrics); + assertThat(metrics.widthPixels).isEqualTo(bounds.width()); + assertThat(metrics.heightPixels).isEqualTo(bounds.height()); + } + + private static FixedRotationAdjustments setOverrideFixedRotationAdjustments( + Resources resources, @Surface.Rotation int rotation) { + FixedRotationAdjustments fixedRotationAdjustments = + setFixedRotationAdjustments(resources, rotation); + resources.overrideDisplayAdjustments( + buildOverrideRotationAdjustments(fixedRotationAdjustments)); + return fixedRotationAdjustments; + } + + private static FixedRotationAdjustments setFixedRotationAdjustments(Resources resources, + @Surface.Rotation int rotation) { + final FixedRotationAdjustments fixedRotationAdjustments = + new FixedRotationAdjustments(rotation, APP_WIDTH, APP_HEIGHT, + DisplayCutout.NO_CUTOUT); + resources.getDisplayAdjustments().setFixedRotationAdjustments(fixedRotationAdjustments); + return fixedRotationAdjustments; + } + + private static Consumer<DisplayAdjustments> buildOverrideRotationAdjustments( + FixedRotationAdjustments fixedRotationAdjustments) { + return consumedDisplayAdjustments + -> consumedDisplayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments); + } +} diff --git a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java index c01bb75c32aa..e41805dd3a59 100644 --- a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java +++ b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java @@ -22,7 +22,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.os.PersistableBundle; import android.os.RemoteException; @@ -32,6 +31,7 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.util.concurrent.Executor; @@ -42,51 +42,23 @@ import java.util.concurrent.Executor; @RunWith(AndroidJUnit4.class) public class RangingManagerTest { - private static final IUwbAdapter ADAPTER = mock(IUwbAdapter.class); private static final Executor EXECUTOR = UwbTestUtils.getExecutor(); private static final PersistableBundle PARAMS = new PersistableBundle(); private static final @RangingChangeReason int REASON = RangingChangeReason.UNKNOWN; @Test public void testOpenSession_OpenRangingInvoked() throws RemoteException { - RangingManager rangingManager = new RangingManager(ADAPTER); + IUwbAdapter adapter = mock(IUwbAdapter.class); + RangingManager rangingManager = new RangingManager(adapter); RangingSession.Callback callback = mock(RangingSession.Callback.class); rangingManager.openSession(PARAMS, EXECUTOR, callback); - verify(ADAPTER, times(1)).openRanging(eq(rangingManager), eq(PARAMS)); - } - - @Test - public void testOpenSession_ErrorIfSameSessionHandleReturned() throws RemoteException { - RangingManager rangingManager = new RangingManager(ADAPTER); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - SessionHandle handle = new SessionHandle(1); - when(ADAPTER.openRanging(any(), any())).thenReturn(handle); - - rangingManager.openSession(PARAMS, EXECUTOR, callback); - - // Calling openSession will cause the same session handle to be returned. The onClosed - // callback should be invoked - RangingSession.Callback callback2 = mock(RangingSession.Callback.class); - rangingManager.openSession(PARAMS, EXECUTOR, callback2); - verify(callback, times(0)).onClosed(anyInt(), any()); - verify(callback2, times(1)).onClosed(anyInt(), any()); - } - - @Test - public void testOnRangingOpened_ValidSessionHandle() throws RemoteException { - RangingManager rangingManager = new RangingManager(ADAPTER); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - SessionHandle handle = new SessionHandle(1); - when(ADAPTER.openRanging(any(), any())).thenReturn(handle); - - rangingManager.openSession(PARAMS, EXECUTOR, callback); - rangingManager.onRangingOpened(handle); - verify(callback, times(1)).onOpened(any()); + verify(adapter, times(1)).openRanging(any(), eq(rangingManager), eq(PARAMS)); } @Test public void testOnRangingOpened_InvalidSessionHandle() throws RemoteException { - RangingManager rangingManager = new RangingManager(ADAPTER); + IUwbAdapter adapter = mock(IUwbAdapter.class); + RangingManager rangingManager = new RangingManager(adapter); RangingSession.Callback callback = mock(RangingSession.Callback.class); rangingManager.onRangingOpened(new SessionHandle(2)); @@ -95,18 +67,20 @@ public class RangingManagerTest { @Test public void testOnRangingOpened_MultipleSessionsRegistered() throws RemoteException { - SessionHandle sessionHandle1 = new SessionHandle(1); - SessionHandle sessionHandle2 = new SessionHandle(2); + IUwbAdapter adapter = mock(IUwbAdapter.class); RangingSession.Callback callback1 = mock(RangingSession.Callback.class); RangingSession.Callback callback2 = mock(RangingSession.Callback.class); + ArgumentCaptor<SessionHandle> sessionHandleCaptor = + ArgumentCaptor.forClass(SessionHandle.class); - when(ADAPTER.openRanging(any(), any())) - .thenReturn(sessionHandle1) - .thenReturn(sessionHandle2); - - RangingManager rangingManager = new RangingManager(ADAPTER); + RangingManager rangingManager = new RangingManager(adapter); rangingManager.openSession(PARAMS, EXECUTOR, callback1); + verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any()); + SessionHandle sessionHandle1 = sessionHandleCaptor.getValue(); + rangingManager.openSession(PARAMS, EXECUTOR, callback2); + verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any()); + SessionHandle sessionHandle2 = sessionHandleCaptor.getValue(); rangingManager.onRangingOpened(sessionHandle1); verify(callback1, times(1)).onOpened(any()); @@ -119,12 +93,17 @@ public class RangingManagerTest { @Test public void testCorrectCallbackInvoked() throws RemoteException { - RangingManager rangingManager = new RangingManager(ADAPTER); + IUwbAdapter adapter = mock(IUwbAdapter.class); + RangingManager rangingManager = new RangingManager(adapter); RangingSession.Callback callback = mock(RangingSession.Callback.class); - SessionHandle handle = new SessionHandle(1); - when(ADAPTER.openRanging(any(), any())).thenReturn(handle); + + ArgumentCaptor<SessionHandle> sessionHandleCaptor = + ArgumentCaptor.forClass(SessionHandle.class); rangingManager.openSession(PARAMS, EXECUTOR, callback); + verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any()); + SessionHandle handle = sessionHandleCaptor.getValue(); + rangingManager.onRangingOpened(handle); verify(callback, times(1)).onOpened(any()); @@ -156,20 +135,23 @@ public class RangingManagerTest { @Test public void testOnRangingClosed_MultipleSessionsRegistered() throws RemoteException { + IUwbAdapter adapter = mock(IUwbAdapter.class); // Verify that if multiple sessions are registered, only the session that is // requested to close receives the associated callbacks - SessionHandle sessionHandle1 = new SessionHandle(1); - SessionHandle sessionHandle2 = new SessionHandle(2); RangingSession.Callback callback1 = mock(RangingSession.Callback.class); RangingSession.Callback callback2 = mock(RangingSession.Callback.class); - when(ADAPTER.openRanging(any(), any())) - .thenReturn(sessionHandle1) - .thenReturn(sessionHandle2); + RangingManager rangingManager = new RangingManager(adapter); + ArgumentCaptor<SessionHandle> sessionHandleCaptor = + ArgumentCaptor.forClass(SessionHandle.class); - RangingManager rangingManager = new RangingManager(ADAPTER); rangingManager.openSession(PARAMS, EXECUTOR, callback1); + verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any()); + SessionHandle sessionHandle1 = sessionHandleCaptor.getValue(); + rangingManager.openSession(PARAMS, EXECUTOR, callback2); + verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any()); + SessionHandle sessionHandle2 = sessionHandleCaptor.getValue(); rangingManager.onRangingClosed(sessionHandle1, REASON, PARAMS); verify(callback1, times(1)).onClosed(anyInt(), any()); @@ -182,19 +164,22 @@ public class RangingManagerTest { @Test public void testOnRangingReport_MultipleSessionsRegistered() throws RemoteException { - SessionHandle sessionHandle1 = new SessionHandle(1); - SessionHandle sessionHandle2 = new SessionHandle(2); + IUwbAdapter adapter = mock(IUwbAdapter.class); RangingSession.Callback callback1 = mock(RangingSession.Callback.class); RangingSession.Callback callback2 = mock(RangingSession.Callback.class); - when(ADAPTER.openRanging(any(), any())) - .thenReturn(sessionHandle1) - .thenReturn(sessionHandle2); + ArgumentCaptor<SessionHandle> sessionHandleCaptor = + ArgumentCaptor.forClass(SessionHandle.class); - RangingManager rangingManager = new RangingManager(ADAPTER); + RangingManager rangingManager = new RangingManager(adapter); rangingManager.openSession(PARAMS, EXECUTOR, callback1); + verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any()); + SessionHandle sessionHandle1 = sessionHandleCaptor.getValue(); + rangingManager.onRangingStarted(sessionHandle1, PARAMS); rangingManager.openSession(PARAMS, EXECUTOR, callback2); + verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any()); + SessionHandle sessionHandle2 = sessionHandleCaptor.getValue(); rangingManager.onRangingStarted(sessionHandle2, PARAMS); rangingManager.onRangingResult(sessionHandle1, UwbTestUtils.getRangingReports(1)); @@ -232,17 +217,24 @@ public class RangingManagerTest { private void runReason(@RangingChangeReason int reasonIn, @RangingSession.Callback.Reason int reasonOut) throws RemoteException { - RangingManager rangingManager = new RangingManager(ADAPTER); + IUwbAdapter adapter = mock(IUwbAdapter.class); + RangingManager rangingManager = new RangingManager(adapter); RangingSession.Callback callback = mock(RangingSession.Callback.class); - SessionHandle handle = new SessionHandle(1); - when(ADAPTER.openRanging(any(), any())).thenReturn(handle); + + ArgumentCaptor<SessionHandle> sessionHandleCaptor = + ArgumentCaptor.forClass(SessionHandle.class); + rangingManager.openSession(PARAMS, EXECUTOR, callback); + verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any()); + SessionHandle handle = sessionHandleCaptor.getValue(); rangingManager.onRangingOpenFailed(handle, reasonIn, PARAMS); verify(callback, times(1)).onOpenFailed(eq(reasonOut), eq(PARAMS)); // Open a new session rangingManager.openSession(PARAMS, EXECUTOR, callback); + verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any()); + handle = sessionHandleCaptor.getValue(); rangingManager.onRangingOpened(handle); rangingManager.onRangingStartFailed(handle, reasonIn, PARAMS); diff --git a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java index 8e7f7c562ade..75c6924a1939 100644 --- a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java +++ b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java @@ -16,34 +16,23 @@ package android.uwb; -import android.content.Context; -import android.content.pm.PackageManager; import android.os.SystemClock; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.Executor; public class UwbTestUtils { private UwbTestUtils() {} - public static boolean isUwbSupported(Context context) { - PackageManager packageManager = context.getPackageManager(); - return packageManager.hasSystemFeature(PackageManager.FEATURE_UWB); - } - public static AngleMeasurement getAngleMeasurement() { - return new AngleMeasurement.Builder() - .setRadians(getDoubleInRange(-Math.PI, Math.PI)) - .setErrorRadians(getDoubleInRange(0, Math.PI)) - .setConfidenceLevel(getDoubleInRange(0, 1)) - .build(); + return new AngleMeasurement( + getDoubleInRange(-Math.PI, Math.PI), + getDoubleInRange(0, Math.PI), + getDoubleInRange(0, 1)); } public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() { - return new AngleOfArrivalMeasurement.Builder() + return new AngleOfArrivalMeasurement.Builder(getAngleMeasurement()) .setAltitude(getAngleMeasurement()) - .setAzimuth(getAngleMeasurement()) .build(); } @@ -69,14 +58,6 @@ public class UwbTestUtils { .build(); } - public static List<RangingMeasurement> getRangingMeasurements(int num) { - List<RangingMeasurement> result = new ArrayList<>(); - for (int i = 0; i < num; i++) { - result.add(getRangingMeasurement()); - } - return result; - } - public static RangingReport getRangingReports(int numMeasurements) { RangingReport.Builder builder = new RangingReport.Builder(); for (int i = 0; i < numMeasurements; i++) { diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index c49fe8563dab..a7b6636a15de 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -488,6 +488,8 @@ applications that come with the platform <permission name="android.permission.MANAGE_UI_TRANSLATION" /> <!-- Permission required for CTS test - ClipboardManagerTest --> <permission name="android.permission.SET_CLIP_SOURCE" /> + <!-- Permission required for CTS test - FontManagerTest --> + <permission name="android.permission.UPDATE_FONTS" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index b7bf8ab75799..4a3bd99b8f7c 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -307,6 +307,12 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "-1777196134": { + "message": "goodToGo(): No apps to animate, mPendingAnimations=%d", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, "-1770075711": { "message": "Adding window client %s that is dead, aborting.", "level": "WARN", @@ -1219,6 +1225,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DragState.java" }, + "-681380736": { + "message": "Sandbox max bounds for uid %s to bounds %s due to letterboxing from mismatch with parent bounds? %s size compat mode %s", + "level": "DEBUG", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-677449371": { "message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b", "level": "DEBUG", @@ -1981,12 +1993,6 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "194124419": { - "message": "goodToGo(): Animation finished already, canceled=%s mPendingAnimations=%d", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, "200829729": { "message": "ScreenRotationAnimation onAnimationEnd", "level": "DEBUG", @@ -2083,6 +2089,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DragState.java" }, + "269976641": { + "message": "goodToGo(): Animation canceled already", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, "274773837": { "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL transit=%s Callers=%s", "level": "VERBOSE", diff --git a/data/keyboards/Vendor_0957_Product_0001.idc b/data/keyboards/Vendor_0957_Product_0001.idc index e1f4346369f3..39479ce725e1 100644 --- a/data/keyboards/Vendor_0957_Product_0001.idc +++ b/data/keyboards/Vendor_0957_Product_0001.idc @@ -19,5 +19,4 @@ # Basic Parameters keyboard.layout = Vendor_0957_Product_0001 -keyboard.characterMap = Vendor_0957_Product_0001 audio.mic = 1
\ No newline at end of file diff --git a/data/keyboards/Vendor_248a_Product_8266.idc b/data/keyboards/Vendor_248a_Product_8266.idc new file mode 100644 index 000000000000..3021655c286e --- /dev/null +++ b/data/keyboards/Vendor_248a_Product_8266.idc @@ -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. + +# +# Input Device Configuration file for Google Reference RCU Remote. +# +# + +# Basic Parameters +# Due to a memory error on early prototypes of the reference remote control +# the VID/PID is mapped to 248a/8266 instead of 0957/0001 +keyboard.layout = Vendor_0957_Product_0001 +audio.mic = 1
\ No newline at end of file diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index c80788269c24..2a6bbf36ef76 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -25,6 +25,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TestApi; import android.annotation.UiThread; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; @@ -169,6 +170,21 @@ public class Typeface { Collections.emptyMap(); /** + * Returns the shared memory that used for creating Typefaces. + * + * @return A SharedMemory used for creating Typeface. Maybe null if the lazy initialization is + * disabled or inside SystemServer or Zygote. + * @hide + */ + @TestApi + public static @Nullable SharedMemory getSystemFontMapSharedMemory() { + if (ENABLE_LAZY_TYPEFACE_INITIALIZATION) { + Objects.requireNonNull(sSystemFontMapSharedMemory); + } + return sSystemFontMapSharedMemory; + } + + /** * @hide */ @UnsupportedAppUsage @@ -1196,8 +1212,13 @@ public class Typeface { } } - /** @hide */ - public static SharedMemory serializeFontMap(Map<String, Typeface> fontMap) + /** + * Create a serialized system font mappings. + * + * @hide + */ + @TestApi + public static @NonNull SharedMemory serializeFontMap(@NonNull Map<String, Typeface> fontMap) throws IOException, ErrnoException { long[] nativePtrs = new long[fontMap.size()]; // The name table will not be large, so let's create a byte array in memory. @@ -1229,9 +1250,14 @@ public class Typeface { } // buffer's byte order should be BIG_ENDIAN. - /** @hide */ - @VisibleForTesting - public static Map<String, Typeface> deserializeFontMap(ByteBuffer buffer) throws IOException { + /** + * Deserialize the font mapping from the serialized byte buffer. + * + * @hide + */ + @TestApi + public static @NonNull Map<String, Typeface> deserializeFontMap(@NonNull ByteBuffer buffer) + throws IOException { Map<String, Typeface> fontMap = new ArrayMap<>(); int typefacesBytesCount = buffer.getInt(); long[] nativePtrs = nativeReadTypefaces(buffer.slice()); diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java index 80f65f919fa6..f3bf63bb3660 100644 --- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java +++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java @@ -27,8 +27,9 @@ import android.graphics.Paint; import android.graphics.RecordingCanvas; import android.graphics.animation.RenderNodeAnimator; import android.util.ArraySet; -import android.view.animation.DecelerateInterpolator; +import android.view.animation.AnimationUtils; import android.view.animation.LinearInterpolator; +import android.view.animation.PathInterpolator; import java.util.function.Consumer; @@ -36,32 +37,41 @@ import java.util.function.Consumer; * @hide */ public final class RippleAnimationSession { - private static final int ENTER_ANIM_DURATION = 350; - private static final int EXIT_ANIM_OFFSET = ENTER_ANIM_DURATION; - private static final int EXIT_ANIM_DURATION = 350; + private static final String TAG = "RippleAnimationSession"; + private static final int ENTER_ANIM_DURATION = 300; + private static final int SLIDE_ANIM_DURATION = 450; + private static final int EXIT_ANIM_DURATION = 300; private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); - // Matches R.interpolator.fast_out_slow_in but as we have no context we can't just import that - private static final TimeInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator(); - + private static final TimeInterpolator PATH_INTERPOLATOR = + new PathInterpolator(.2f, 0, 0, 1f); private Consumer<RippleAnimationSession> mOnSessionEnd; - private AnimationProperties<Float, Paint> mProperties; + private final AnimationProperties<Float, Paint> mProperties; private AnimationProperties<CanvasProperty<Float>, CanvasProperty<Paint>> mCanvasProperties; private Runnable mOnUpdate; private long mStartTime; private boolean mForceSoftware; - private ArraySet<Animator> mActiveAnimations = new ArraySet(3); + private final float mWidth, mHeight; + private final ValueAnimator mSparkle = ValueAnimator.ofFloat(0, 1); + private final ArraySet<Animator> mActiveAnimations = new ArraySet<>(3); RippleAnimationSession(@NonNull AnimationProperties<Float, Paint> properties, - boolean forceSoftware) { + boolean forceSoftware, float width, float height) { mProperties = properties; mForceSoftware = forceSoftware; - } - - void end() { - for (Animator anim: mActiveAnimations) { - if (anim != null) anim.end(); - } - mActiveAnimations.clear(); + mWidth = width; + mHeight = height; + + mSparkle.addUpdateListener(anim -> { + final long now = AnimationUtils.currentAnimationTimeMillis(); + final long elapsed = now - mStartTime - ENTER_ANIM_DURATION; + final float phase = (float) elapsed / 1000f; + mProperties.getShader().setSecondsOffset(phase); + notifyUpdate(); + }); + mSparkle.setDuration(ENTER_ANIM_DURATION); + mSparkle.setStartDelay(ENTER_ANIM_DURATION); + mSparkle.setInterpolator(LINEAR_INTERPOLATOR); + mSparkle.setRepeatCount(ValueAnimator.INFINITE); } @NonNull RippleAnimationSession enter(Canvas canvas) { @@ -70,17 +80,19 @@ public final class RippleAnimationSession { } else { enterSoftware(); } - mStartTime = System.nanoTime(); + mStartTime = AnimationUtils.currentAnimationTimeMillis(); return this; } @NonNull RippleAnimationSession exit(Canvas canvas) { + mSparkle.end(); if (isHwAccelerated(canvas)) exitHardware((RecordingCanvas) canvas); else exitSoftware(); return this; } private void onAnimationEnd(Animator anim) { + notifyUpdate(); mActiveAnimations.remove(anim); } @@ -92,7 +104,6 @@ public final class RippleAnimationSession { RippleAnimationSession setOnAnimationUpdated(@Nullable Runnable run) { mOnUpdate = run; - mProperties.setOnChange(mOnUpdate); return this; } @@ -122,14 +133,12 @@ public final class RippleAnimationSession { } private long computeDelay() { - long currentTime = System.nanoTime(); - long timePassed = (currentTime - mStartTime) / 1_000_000; - long difference = EXIT_ANIM_OFFSET; - return Math.max(difference - timePassed, 0); + final long timePassed = AnimationUtils.currentAnimationTimeMillis() - mStartTime; + return Math.max((long) SLIDE_ANIM_DURATION - timePassed, 0); } + private void notifyUpdate() { - Runnable onUpdate = mOnUpdate; - if (onUpdate != null) onUpdate.run(); + if (mOnUpdate != null) mOnUpdate.run(); } RippleAnimationSession setForceSoftwareAnimation(boolean forceSw) { @@ -153,7 +162,7 @@ public final class RippleAnimationSession { } }); exit.setTarget(canvas); - exit.setInterpolator(DECELERATE_INTERPOLATOR); + exit.setInterpolator(LINEAR_INTERPOLATOR); long delay = computeDelay(); exit.setStartDelay(delay); @@ -161,36 +170,67 @@ public final class RippleAnimationSession { mActiveAnimations.add(exit); } - private void enterHardware(RecordingCanvas can) { + private void enterHardware(RecordingCanvas canvas) { AnimationProperties<CanvasProperty<Float>, CanvasProperty<Paint>> props = getCanvasProperties(); RenderNodeAnimator expand = new RenderNodeAnimator(props.getProgress(), .5f); - expand.setTarget(can); - expand.setDuration(ENTER_ANIM_DURATION); - expand.addListener(new AnimatorListener(this)); + RenderNodeAnimator slideX = + new RenderNodeAnimator(props.getX(), mWidth / 2); + RenderNodeAnimator slideY = + new RenderNodeAnimator(props.getY(), mHeight / 2); + expand.setTarget(canvas); + slideX.setTarget(canvas); + slideY.setTarget(canvas); + startAnimation(expand, slideX, slideY); + } + + private void startAnimation(Animator expand, + Animator slideX, Animator slideY) { + expand.setDuration(SLIDE_ANIM_DURATION); + slideX.setDuration(SLIDE_ANIM_DURATION); + slideY.setDuration(SLIDE_ANIM_DURATION); + slideX.addListener(new AnimatorListener(this)); expand.setInterpolator(LINEAR_INTERPOLATOR); + slideX.setInterpolator(PATH_INTERPOLATOR); + slideY.setInterpolator(PATH_INTERPOLATOR); expand.start(); + slideX.start(); + slideY.start(); + if (!mSparkle.isRunning()) { + mSparkle.start(); + mActiveAnimations.add(mSparkle); + } mActiveAnimations.add(expand); + mActiveAnimations.add(slideX); + mActiveAnimations.add(slideY); } private void enterSoftware() { ValueAnimator expand = ValueAnimator.ofFloat(0f, 0.5f); + ValueAnimator slideX = ValueAnimator.ofFloat( + mProperties.getX(), mWidth / 2); + ValueAnimator slideY = ValueAnimator.ofFloat( + mProperties.getY(), mHeight / 2); expand.addUpdateListener(updatedAnimation -> { notifyUpdate(); mProperties.getShader().setProgress((Float) expand.getAnimatedValue()); }); - expand.addListener(new AnimatorListener(this)); - expand.setInterpolator(LINEAR_INTERPOLATOR); - expand.start(); - mActiveAnimations.add(expand); + slideX.addUpdateListener(anim -> { + float x = (float) slideX.getAnimatedValue(); + float y = (float) slideY.getAnimatedValue(); + mProperties.setOrigin(x, y); + mProperties.getShader().setOrigin(x, y); + }); + startAnimation(expand, slideX, slideY); } @NonNull AnimationProperties<Float, Paint> getProperties() { return mProperties; } - @NonNull AnimationProperties getCanvasProperties() { + @NonNull + AnimationProperties<CanvasProperty<Float>, CanvasProperty<Paint>> getCanvasProperties() { if (mCanvasProperties == null) { mCanvasProperties = new AnimationProperties<>( CanvasProperty.createFloat(mProperties.getX()), @@ -209,6 +249,7 @@ public final class RippleAnimationSession { AnimatorListener(RippleAnimationSession session) { mSession = session; } + @Override public void onAnimationStart(Animator animation) { @@ -231,21 +272,12 @@ public final class RippleAnimationSession { } static class AnimationProperties<FloatType, PaintType> { - private final FloatType mY; - private FloatType mProgress; - private FloatType mMaxRadius; + private final FloatType mProgress; + private final FloatType mMaxRadius; private final PaintType mPaint; - private final FloatType mX; private final RippleShader mShader; - private Runnable mOnChange; - - private void onChange() { - if (mOnChange != null) mOnChange.run(); - } - - private void setOnChange(Runnable onChange) { - mOnChange = onChange; - } + private FloatType mX; + private FloatType mY; AnimationProperties(FloatType x, FloatType y, FloatType maxRadius, PaintType paint, FloatType progress, RippleShader shader) { @@ -261,6 +293,11 @@ public final class RippleAnimationSession { return mProgress; } + void setOrigin(FloatType x, FloatType y) { + mX = x; + mY = y; + } + FloatType getX() { return mX; } diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 5024875aab3c..d6bbee90d73b 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -48,6 +48,7 @@ import android.graphics.RecordingCanvas; import android.graphics.Rect; import android.graphics.Shader; import android.os.Build; +import android.os.SystemProperties; import android.util.AttributeSet; import android.view.animation.LinearInterpolator; @@ -109,17 +110,6 @@ import java.util.Arrays; * </pre> * * @attr ref android.R.styleable#RippleDrawable_color - * - * To change the ripple style, assign the value of "solid" or "patterned" to the android:rippleStyle - * attribute. - * - * <pre> - * <code><!-- A red ripple masked against an opaque rectangle. --/> - * <ripple android:rippleStyle="patterned"> - * </ripple></code> - * </pre> - * - * @attr ref android.R.styleable#RippleDrawable_rippleStyle */ public class RippleDrawable extends LayerDrawable { /** @@ -131,12 +121,14 @@ public class RippleDrawable extends LayerDrawable { /** * Ripple style where a solid circle is drawn. This is also the default style * @see #setRippleStyle(int) + * @hide */ public static final int STYLE_SOLID = 0; /** * Ripple style where a circle shape with a patterned, * noisy interior expands from the hotspot to the bounds". * @see #setRippleStyle(int) + * @hide */ public static final int STYLE_PATTERNED = 1; @@ -159,6 +151,9 @@ public class RippleDrawable extends LayerDrawable { /** The maximum number of ripples supported. */ private static final int MAX_RIPPLES = 10; private static final LinearInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); + /** Temporary flag for teamfood. **/ + private static final boolean FORCE_PATTERNED_STYLE = + SystemProperties.getBoolean("persist.material.patternedripple", false); private final Rect mTempRect = new Rect(); @@ -361,7 +356,9 @@ public class RippleDrawable extends LayerDrawable { } } else { if (focused || hovered) { - enterPatternedBackgroundAnimation(focused, hovered); + if (!pressed) { + enterPatternedBackgroundAnimation(focused, hovered); + } } else { exitPatternedBackgroundAnimation(); } @@ -571,7 +568,10 @@ public class RippleDrawable extends LayerDrawable { mState.mMaxRadius = a.getDimensionPixelSize( R.styleable.RippleDrawable_radius, mState.mMaxRadius); - mState.mRippleStyle = a.getInteger(R.styleable.RippleDrawable_rippleStyle, STYLE_SOLID); + if (!FORCE_PATTERNED_STYLE) { + mState.mRippleStyle = a.getInteger(R.styleable.RippleDrawable_rippleStyle, + mState.mRippleStyle); + } } private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException { @@ -812,21 +812,25 @@ public class RippleDrawable extends LayerDrawable { } private void drawPatterned(@NonNull Canvas canvas) { - final Rect bounds = getBounds(); + final Rect bounds = getDirtyBounds(); final int saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG); boolean useCanvasProps = shouldUseCanvasProps(canvas); boolean changedHotspotBounds = !bounds.equals(mHotspotBounds); if (isBounded()) { - canvas.clipRect(mHotspotBounds); + canvas.clipRect(bounds); } - float x, y; + float x, y, w, h; if (changedHotspotBounds) { x = mHotspotBounds.exactCenterX(); y = mHotspotBounds.exactCenterY(); + w = mHotspotBounds.width(); + h = mHotspotBounds.height(); useCanvasProps = false; } else { x = mPendingX; y = mPendingY; + w = bounds.width(); + h = bounds.height(); } boolean shouldAnimate = mRippleActive; boolean shouldExit = mExitingAnimation; @@ -837,9 +841,9 @@ public class RippleDrawable extends LayerDrawable { drawPatternedBackground(canvas); if (shouldAnimate && mRunningAnimations.size() <= MAX_RIPPLES) { RippleAnimationSession.AnimationProperties<Float, Paint> properties = - createAnimationProperties(x, y); - mRunningAnimations.add(new RippleAnimationSession(properties, !useCanvasProps) - .setOnAnimationUpdated(useCanvasProps ? null : () -> invalidateSelf(false)) + createAnimationProperties(x, y, w, h); + mRunningAnimations.add(new RippleAnimationSession(properties, !useCanvasProps, w, h) + .setOnAnimationUpdated(() -> invalidateSelf(false)) .setOnSessionEnd(session -> { mRunningAnimations.remove(session); }) @@ -864,20 +868,8 @@ public class RippleDrawable extends LayerDrawable { } else { RippleAnimationSession.AnimationProperties<Float, Paint> p = s.getProperties(); - float posX, posY; - if (changedHotspotBounds) { - posX = x; - posY = y; - if (p.getPaint().getShader() instanceof RippleShader) { - RippleShader shader = (RippleShader) p.getPaint().getShader(); - shader.setOrigin(posX, posY); - } - } else { - posX = p.getX(); - posY = p.getY(); - } float radius = p.getMaxRadius(); - canvas.drawCircle(posX, posY, radius, p.getPaint()); + canvas.drawCircle(p.getX(), p.getY(), radius, p.getPaint()); } } canvas.restoreToCount(saveCount); @@ -905,14 +897,13 @@ public class RippleDrawable extends LayerDrawable { private float computeRadius() { Rect b = getDirtyBounds(); - float gap = 0; - float radius = (float) Math.sqrt(b.width() * b.width() + b.height() * b.height()) / 2 + gap; + float radius = (float) Math.sqrt(b.width() * b.width() + b.height() * b.height()) / 2; return radius; } @NonNull private RippleAnimationSession.AnimationProperties<Float, Paint> createAnimationProperties( - float x, float y) { + float x, float y, float w, float h) { Paint p = new Paint(mRipplePaint); float radius = mState.mMaxRadius; RippleAnimationSession.AnimationProperties<Float, Paint> properties; @@ -920,19 +911,19 @@ public class RippleDrawable extends LayerDrawable { int color = mMaskColorFilter == null ? mState.mColor.getColorForState(getState(), Color.BLACK) : mMaskColorFilter.getColor(); - color = color | 0xFF000000; shader.setColor(color); shader.setOrigin(x, y); + shader.setResolution(w, h); + shader.setSecondsOffset(0); shader.setRadius(radius); shader.setProgress(.0f); properties = new RippleAnimationSession.AnimationProperties<>( x, y, radius, p, 0f, shader); if (mMaskShader == null) { - shader.setHasMask(false); + shader.setShader(null); } else { shader.setShader(mMaskShader); - shader.setHasMask(true); } p.setShader(shader); p.setColorFilter(null); @@ -1160,7 +1151,7 @@ public class RippleDrawable extends LayerDrawable { // The ripple timing depends on the paint's alpha value, so we need // to push just the alpha channel into the paint and let the filter // handle the full-alpha color. - int maskColor = color | 0xFF000000; + int maskColor = mState.mRippleStyle == STYLE_PATTERNED ? color : color | 0xFF000000; if (mMaskColorFilter.getColor() != maskColor) { mMaskColorFilter = new PorterDuffColorFilter(maskColor, mMaskColorFilter.getMode()); } @@ -1248,6 +1239,7 @@ public class RippleDrawable extends LayerDrawable { * @see #STYLE_PATTERNED * * @param style The style of the ripple + * @hide */ public void setRippleStyle(@RippleStyle int style) throws IllegalArgumentException { if (style == STYLE_SOLID || style == STYLE_PATTERNED) { @@ -1260,6 +1252,7 @@ public class RippleDrawable extends LayerDrawable { /** * Get the current ripple style * @return Ripple style + * @hide */ public @RippleStyle int getRippleStyle() { return mState.mRippleStyle; @@ -1276,7 +1269,7 @@ public class RippleDrawable extends LayerDrawable { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) ColorStateList mColor = ColorStateList.valueOf(Color.MAGENTA); int mMaxRadius = RADIUS_AUTO; - int mRippleStyle = STYLE_SOLID; + int mRippleStyle = FORCE_PATTERNED_STYLE ? STYLE_PATTERNED : STYLE_SOLID; public RippleState(LayerState orig, RippleDrawable owner, Resources res) { super(orig, owner, res); diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java index 500efdd84854..25492779e6e9 100644 --- a/graphics/java/android/graphics/drawable/RippleShader.java +++ b/graphics/java/android/graphics/drawable/RippleShader.java @@ -17,58 +17,153 @@ package android.graphics.drawable; import android.annotation.ColorInt; -import android.annotation.NonNull; import android.graphics.Color; import android.graphics.RuntimeShader; import android.graphics.Shader; final class RippleShader extends RuntimeShader { - private static final String SHADER = "uniform float2 in_origin;\n" - + "uniform float in_maxRadius;\n" + private static final String SHADER_UNIFORMS = "uniform vec2 in_origin;\n" + "uniform float in_progress;\n" + + "uniform float in_maxRadius;\n" + + "uniform vec2 in_resolution;\n" + "uniform float in_hasMask;\n" - + "uniform float4 in_color;\n" - + "uniform shader in_shader;\n" - + "float dist2(float2 p0, float2 pf) { return sqrt((pf.x - p0.x) * (pf.x - p0.x) + " - + "(pf.y - p0.y) * (pf.y - p0.y)); }\n" - + "float mod2(float a, float b) { return a - (b * floor(a / b)); }\n" - + "float rand(float2 src) { return fract(sin(dot(src.xy, float2(12.9898, 78.233))) * " - + "43758.5453123); }\n" - + "float4 main(float2 p)\n" - + "{\n" - + " float fraction = in_progress;\n" - + " float2 fragCoord = p;//sk_FragCoord.xy;\n" - + " float maxDist = in_maxRadius;\n" - + " float fragDist = dist2(in_origin, fragCoord.xy);\n" - + " float circleRadius = maxDist * fraction;\n" - + " float colorVal = (fragDist - circleRadius) / maxDist;\n" - + " float d = fragDist < circleRadius \n" - + " ? 1. - abs(colorVal * 3. * smoothstep(0., 1., fraction)) \n" - + " : 1. - abs(colorVal * 5.);\n" - + " d = smoothstep(0., 1., d);\n" - + " float divider = 2.;\n" - + " float x = floor(fragCoord.x / divider);\n" - + " float y = floor(fragCoord.y / divider);\n" - + " float density = .95;\n" - + " d = rand(float2(x, y)) > density ? d : d * .2;\n" - + " d = d * rand(float2(fraction, x * y));\n" - + " float alpha = 1. - pow(fraction, 2.);\n" - + " if (in_hasMask != 0.) {return sample(in_shader).a * in_color * d * alpha;}\n" - + " return in_color * d * alpha;\n" + + "uniform float in_secondsOffset;\n" + + "uniform vec4 in_color;\n" + + "uniform shader in_shader;\n"; + private static final String SHADER_LIB = + "float triangleNoise(vec2 n) {\n" + + " n = fract(n * vec2(5.3987, 5.4421));\n" + + " n += dot(n.yx, n.xy + vec2(21.5351, 14.3137));\n" + + " float xy = n.x * n.y;\n" + + " return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;\n" + + "}" + + "const float PI = 3.1415926535897932384626;\n" + + "\n" + + "float threshold(float v, float l, float h) {\n" + + " return step(l, v) * (1.0 - step(h, v));\n" + + "}\n" + + "\n" + + "float sparkles(vec2 uv, float t) {\n" + + " float n = triangleNoise(uv);\n" + + " float s = 0.0;\n" + + " for (float i = 0; i < 4; i += 1) {\n" + + " float l = i * 0.25;\n" + + " float h = l + 0.025;\n" + + " float o = abs(sin(0.1 * PI * (t + i)));\n" + + " s += threshold(n + o, l, h);\n" + + " }\n" + + " return saturate(s);\n" + + "}\n" + + "\n" + + "float softCircle(vec2 uv, vec2 xy, float radius, float blur) {\n" + + " float blurHalf = blur * 0.5;\n" + + " float d = distance(uv, xy);\n" + + " return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius);\n" + + "}\n" + + "\n" + + "float softRing(vec2 uv, vec2 xy, float radius, float blur) {\n" + + " float thickness = 0.4;\n" + + " float circle_outer = softCircle(uv, xy, radius + thickness * 0.5, blur);\n" + + " float circle_inner = softCircle(uv, xy, radius - thickness * 0.5, blur);\n" + + " return circle_outer - circle_inner;\n" + + "}\n" + + "\n" + + "struct Viewport {\n" + + " float aspect;\n" + + " vec2 uv;\n" + + " vec2 resolution_pixels;\n" + + "};\n" + + "\n" + + "Viewport getViewport(vec2 frag_coord, vec2 resolution_pixels) {\n" + + " Viewport v;\n" + + " v.aspect = resolution_pixels.y / resolution_pixels.x;\n" + + " v.uv = frag_coord / resolution_pixels;\n" + + " v.uv.y = (1.0 - v.uv.y) * v.aspect;\n" + + " v.resolution_pixels = resolution_pixels;\n" + + " return v;\n" + + "}\n" + + "\n" + + "vec2 getTouch(vec2 touch_position_pixels, Viewport viewport) {\n" + + " vec2 touch = touch_position_pixels / viewport.resolution_pixels;\n" + + " touch.y *= viewport.aspect;\n" + + " return touch;\n" + + "}\n" + + "\n" + + "struct Wave {\n" + + " float ring;\n" + + " float circle;\n" + + "};\n" + + "\n" + + "Wave getWave(Viewport viewport, vec2 touch, float progress) {\n" + + " float fade = pow((clamp(progress, 0.8, 1.0)), 8.);\n" + + " Wave w;\n" + + " w.ring = max(softRing(viewport.uv, touch, progress, 0.45) - fade, 0.);\n" + + " w.circle = softCircle(viewport.uv, touch, 2.0 * progress, 0.2) - progress;\n" + + " return w;\n" + + "}\n" + + "\n" + + "vec4 getRipple(vec4 color, float loudness, float sparkle, Wave wave) {\n" + + " float alpha = wave.ring * sparkle * loudness\n" + + " + wave.circle * color.a;\n" + + " return vec4(color.rgb, saturate(alpha));\n" + + "}\n" + + "\n" + + "float getRingMask(vec2 frag, vec2 center, float r, float progress) {\n" + + " float dist = distance(frag, center);\n" + + " float expansion = r * .6;\n" + + " r = r * min(1.,progress);\n" + + " float minD = max(r - expansion, 0.);\n" + + " float maxD = r + expansion;\n" + + " if (dist > maxD || dist < minD) return .0;\n" + + " return min(maxD - dist, dist - minD) / expansion; \n" + + "}\n" + + "\n" + + "float subProgress(float start, float end, float progress) {\n" + + " float sub = clamp(progress, start, end);\n" + + " return (sub - start) / (end - start); \n" + "}\n"; + private static final String SHADER_MAIN = "vec4 main(vec2 p) {\n" + + " float fadeIn = subProgress(0., 0.175, in_progress);\n" + + " float fadeOutNoise = subProgress(0.375, 1., in_progress);\n" + + " float fadeOutRipple = subProgress(0.375, 0.75, in_progress);\n" + + " Viewport vp = getViewport(p, in_resolution);\n" + + " vec2 touch = getTouch(in_origin, vp);\n" + + " Wave w = getWave(vp, touch, in_progress * 0.25);\n" + + " float ring = getRingMask(p, in_origin, in_maxRadius, fadeIn);\n" + + " float alpha = min(fadeIn, 1. - fadeOutNoise);\n" + + " float sparkle = sparkles(p, in_progress * 0.25 + in_secondsOffset)\n" + + " * ring * alpha;\n" + + " vec4 r = getRipple(in_color, 1., sparkle, w);\n" + + " float fade = min(fadeIn, 1.-fadeOutRipple);\n" + + " vec4 circle = vec4(in_color.rgb, softCircle(p, in_origin, in_maxRadius " + + " * fadeIn, 0.2) * fade * in_color.a);\n" + + " float mask = in_hasMask == 1. ? sample(in_shader).a > 0. ? 1. : 0. : 1.;\n" + + " return mix(circle, vec4(1.), sparkle * mask);\n" + + "}"; + private static final String SHADER = SHADER_UNIFORMS + SHADER_LIB + SHADER_MAIN; RippleShader() { super(SHADER, false); } - public void setShader(@NonNull Shader s) { - setInputShader("in_shader", s); + public void setShader(Shader shader) { + if (shader != null) { + setInputShader("in_shader", shader); + } + setUniform("in_hasMask", shader == null ? 0 : 1); } public void setRadius(float radius) { setUniform("in_maxRadius", radius); } + /** + * Continuous offset used as noise phase. + */ + public void setSecondsOffset(float t) { + setUniform("in_secondsOffset", t); + } + public void setOrigin(float x, float y) { setUniform("in_origin", new float[] {x, y}); } @@ -77,13 +172,16 @@ final class RippleShader extends RuntimeShader { setUniform("in_progress", progress); } - public void setHasMask(boolean hasMask) { - setUniform("in_hasMask", hasMask ? 1 : 0); - } - + /** + * Color of the circle that's under the sparkles. Sparkles will always be white. + */ public void setColor(@ColorInt int colorIn) { Color color = Color.valueOf(colorIn); this.setUniform("in_color", new float[] {color.red(), color.green(), color.blue(), color.alpha()}); } + + public void setResolution(float w, float h) { + setUniform("in_resolution", w, h); + } } diff --git a/graphics/java/android/graphics/fonts/FontFileUtil.java b/graphics/java/android/graphics/fonts/FontFileUtil.java index af49619fb840..917eef2ffede 100644 --- a/graphics/java/android/graphics/fonts/FontFileUtil.java +++ b/graphics/java/android/graphics/fonts/FontFileUtil.java @@ -183,6 +183,23 @@ public class FontFileUtil { return nIsPostScriptType1Font(buffer, index); } + /** + * Analyze the file content and returns 1 if the font file is an OpenType collection file, 0 if + * the font file is a OpenType font file, -1 otherwise. + */ + public static int isCollectionFont(@NonNull ByteBuffer buffer) { + ByteBuffer copied = buffer.slice(); + copied.order(ByteOrder.BIG_ENDIAN); + int magicNumber = copied.getInt(0); + if (magicNumber == TTC_TAG) { + return 1; + } else if (magicNumber == SFNT_VERSION_1 || magicNumber == SFNT_VERSION_OTTO) { + return 0; + } else { + return -1; + } + } + @FastNative private static native long nGetFontRevision(@NonNull ByteBuffer buffer, @IntRange(from = 0) int index); diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java index ed789f03f9ba..55015696ff47 100644 --- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java +++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.ServiceManager; import android.os.ServiceSpecificException; -import android.security.usermanager.IKeystoreUserManager; +import android.security.maintenance.IKeystoreMaintenance; import android.system.keystore2.Domain; import android.system.keystore2.ResponseCode; import android.util.Log; @@ -34,9 +34,9 @@ public class AndroidKeyStoreMaintenance { public static final int SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR; - private static IKeystoreUserManager getService() { - return IKeystoreUserManager.Stub.asInterface( - ServiceManager.checkService("android.security.usermanager")); + private static IKeystoreMaintenance getService() { + return IKeystoreMaintenance.Stub.asInterface( + ServiceManager.checkService("android.security.maintenance")); } /** diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java index f48da74eb397..cd77d9c2723f 100644 --- a/keystore/java/android/security/keystore/AttestationUtils.java +++ b/keystore/java/android/security/keystore/AttestationUtils.java @@ -22,7 +22,6 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.Context; import android.os.Build; -import android.security.KeyStore; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterCertificateChain; import android.security.keymaster.KeymasterDefs; @@ -32,9 +31,14 @@ import android.util.ArraySet; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.SecureRandom; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.spec.ECGenParameterSpec; import java.util.Collection; +import java.util.Random; import java.util.Set; /** @@ -223,22 +227,47 @@ public abstract class AttestationUtils { @NonNull public static X509Certificate[] attestDeviceIds(Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws DeviceIdAttestationException { - final KeymasterArguments attestArgs = prepareAttestationArgumentsForDeviceId( - context, idTypes, attestationChallenge); - - // Perform attestation. - final KeymasterCertificateChain outChain = new KeymasterCertificateChain(); - final int errorCode = KeyStore.getInstance().attestDeviceIds(attestArgs, outChain); - if (errorCode != KeyStore.NO_ERROR) { - throw new DeviceIdAttestationException("Unable to perform attestation", - KeyStore.getKeyStoreException(errorCode)); + String keystoreAlias = generateRandomAlias(); + KeyGenParameterSpec.Builder builder = + new KeyGenParameterSpec.Builder(keystoreAlias, KeyProperties.PURPOSE_SIGN) + .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) + .setDigests(KeyProperties.DIGEST_SHA256) + .setAttestationChallenge(attestationChallenge); + + if (idTypes != null) { + builder.setAttestationIds(idTypes); + builder.setDevicePropertiesAttestationIncluded(true); } try { - return parseCertificateChain(outChain); - } catch (KeyAttestationException e) { - throw new DeviceIdAttestationException(e.getMessage(), e); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( + KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore"); + keyPairGenerator.initialize(builder.build()); + keyPairGenerator.generateKeyPair(); + + KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); + keyStore.load(null); + + X509Certificate[] certificateChain = + (X509Certificate[]) keyStore.getCertificateChain(keystoreAlias); + + keyStore.deleteEntry(keystoreAlias); + + return certificateChain; + } catch (Exception e) { + throw new DeviceIdAttestationException("Unable to perform attestation", e); + } + } + + private static String generateRandomAlias() { + Random random = new SecureRandom(); + StringBuilder builder = new StringBuilder(); + // Pick random uppercase letters, A-Z. 20 of them gives us ~94 bits of entropy, which + // should prevent any conflicts with app-selected aliases, even for very unlucky users. + for (int i = 0; i < 20; ++i) { + builder.append(random.nextInt(26) + 'A'); } + return builder.toString(); } /** diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 72735a787b7f..5cb2c3b41517 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -467,8 +467,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * * @return The numeric namespace as configured in the keystore2_key_contexts files of Android's * SEPolicy. - * TODO b/171806779 link to public Keystore 2.0 documentation. - * See bug for more details for now. + * See <a href="https://source.android.com/security/keystore#access-control"> + * Keystore 2.0 access control</a> * @hide */ @SystemApi @@ -1042,9 +1042,9 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * keys between system and vendor components, e.g., WIFI settings and WPA supplicant. * * @param namespace Numeric SELinux namespace as configured in keystore2_key_contexts - * of Android's SEPolicy. - * TODO b/171806779 link to public Keystore 2.0 documentation. - * See bug for more details for now. + * of Android's SEPolicy. + * See <a href="https://source.android.com/security/keystore#access-control"> + * Keystore 2.0 access control</a> * @return this Builder object. * * @hide diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java index d36695b9b410..fa852e33a1d8 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java @@ -340,11 +340,11 @@ public class AndroidKeyStoreProvider extends Provider { * @param keyStore The keystore2 backend. * @param alias The alias of the key in the Keystore database. * @param namespace The a Keystore namespace. This is used by system api only to request - * Android system specific keystore namespace, which can be configured - * in the device's SEPolicy. Third party apps and most system components - * set this parameter to -1 to indicate their application specific namespace. - * TODO b/171806779 link to public Keystore 2.0 documentation. - * See bug for more details for now. + * Android system specific keystore namespace, which can be configured + * in the device's SEPolicy. Third party apps and most system components + * set this parameter to -1 to indicate their application specific namespace. + * See <a href="https://source.android.com/security/keystore#access-control"> + * Keystore 2.0 access control</a> * @hide **/ @NonNull diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml index c0bc73dcbd47..d2b3cf6a4fe2 100644 --- a/libs/WindowManager/Shell/AndroidManifest.xml +++ b/libs/WindowManager/Shell/AndroidManifest.xml @@ -18,4 +18,5 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.wm.shell"> <uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" /> + <uses-permission android:name="android.permission.READ_FRAME_BUFFER" /> </manifest> diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml index 24198659e15d..c2f591b9d7af 100644 --- a/libs/WindowManager/Shell/res/values/config.xml +++ b/libs/WindowManager/Shell/res/values/config.xml @@ -51,4 +51,10 @@ <!-- 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> + + <!-- Animation duration when exit starting window: reveal app --> + <integer name="starting_window_app_reveal_anim_duration">333</integer> </resources> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 75bed3777a9d..3ced8d3ec6e7 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -188,4 +188,13 @@ <!-- The height of the brand image on staring surface. --> <dimen name="starting_surface_brand_image_height">80dp</dimen> + + <!-- The length of the shift of main window when exit starting window. --> + <dimen name="starting_surface_exit_animation_window_shift_length">20dp</dimen> + + <!-- The distance of the shift icon when normal exit starting window. --> + <dimen name="starting_surface_normal_exit_icon_distance">120dp</dimen> + + <!-- The distance of the shift icon when early exit starting window. --> + <dimen name="starting_surface_early_exit_icon_distance">32dp</dimen> </resources> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index cb04bd7ce02b..fcb53cd890b7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -31,6 +31,7 @@ import android.app.ActivityManager.RunningTaskInfo; import android.app.TaskInfo; import android.content.Context; import android.content.LocusId; +import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; import android.util.ArrayMap; @@ -307,9 +308,10 @@ public class ShellTaskOrganizer extends TaskOrganizer { } @Override - public void removeStartingWindow(int taskId) { + public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { if (mStartingSurface != null) { - mStartingSurface.removeStartingWindow(taskId); + mStartingSurface.removeStartingWindow(taskId, leash, frame, playRevealAnimation); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java index 46884fefd69c..7d65a08ce798 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java @@ -83,6 +83,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, private boolean mIsInitialized; private Listener mListener; private Executor mListenerExecutor; + private Rect mObscuredTouchRect; private final Rect mTmpRect = new Rect(); private final Rect mTmpRootRect = new Rect(); @@ -161,6 +162,15 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, } /** + * Indicates a region of the view that is not touchable. + * + * @param obscuredRect the obscured region of the view. + */ + public void setObscuredTouchRect(Rect obscuredRect) { + mObscuredTouchRect = obscuredRect; + } + + /** * Call when view position or size has changed. Do not call when animating. */ public void onLocationChanged() { @@ -384,6 +394,10 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, mTmpRect.set(mTmpLocation[0], mTmpLocation[1], mTmpLocation[0] + getWidth(), mTmpLocation[1] + getHeight()); inoutInfo.touchableRegion.op(mTmpRect, Region.Op.DIFFERENCE); + + if (mObscuredTouchRect != null) { + inoutInfo.touchableRegion.union(mObscuredTouchRect); + } } @Override 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 64a44ca9e7e9..16ede735660f 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 @@ -41,7 +41,6 @@ import android.graphics.Paint; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; -import android.graphics.Region; import android.os.Bundle; import android.provider.Settings; import android.util.Log; @@ -1046,6 +1045,7 @@ public class BubbleStackView extends FrameLayout } }; + // TODO: Create ManageMenuView and move setup / animations there private void setUpManageMenu() { if (mManageMenu != null) { removeView(mManageMenu); @@ -2146,50 +2146,6 @@ public class BubbleStackView extends FrameLayout } /** - * This method is called by {@link android.app.ActivityView} because the BubbleStackView has a - * higher Z-index than the ActivityView (so that dragged-out bubbles are visible over the AV). - * ActivityView is asking BubbleStackView to subtract the stack's bounds from the provided - * touchable region, so that the ActivityView doesn't consume events meant for the stack. Due to - * the special nature of ActivityView, it does not respect the standard - * {@link #dispatchTouchEvent} and {@link #onInterceptTouchEvent} methods typically used for - * this purpose. - * - * BubbleStackView is MATCH_PARENT, so that bubbles can be positioned via their translation - * properties for performance reasons. This means that the default implementation of this method - * subtracts the entirety of the screen from the ActivityView's touchable region, resulting in - * it not receiving any touch events. This was previously addressed by returning false in the - * stack's {@link View#canReceivePointerEvents()} method, but this precluded the use of any - * touch handlers in the stack or its child views. - * - * To support touch handlers, we're overriding this method to leave the ActivityView's touchable - * region alone. The only touchable part of the stack that can ever overlap the AV is a - * dragged-out bubble that is animating back into the row of bubbles. It's not worth continually - * updating the touchable region to allow users to grab a bubble while it completes its ~50ms - * animation back to the bubble row. - * - * NOTE: Any future additions to the stack that obscure the ActivityView region will need their - * bounds subtracted here in order to receive touch events. - */ - @Override - public void subtractObscuredTouchableRegion(Region touchableRegion, View view) { - // If the notification shade is expanded, or the manage menu is open, or we are showing - // manage bubbles user education, we shouldn't let the ActivityView steal any touch events - // from any location. - if (!mIsExpanded - || mShowingManage - || (mManageEduView != null - && mManageEduView.getVisibility() == VISIBLE)) { - touchableRegion.setEmpty(); - } - } - - /** - * If you're here because you're not receiving touch events on a view that is a descendant of - * BubbleStackView, and you think BSV is intercepting them - it's not! You need to subtract the - * bounds of the view in question in {@link #subtractObscuredTouchableRegion}. The ActivityView - * consumes all touch events within its bounds, even for views like the BubbleStackView that are - * above it. It ignores typical view touch handling methods like this one and - * dispatchTouchEvent. */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { @@ -2539,6 +2495,11 @@ public class BubbleStackView extends FrameLayout } mExpandedBubble.getExpandedView().getManageButtonBoundsOnScreen(mTempRect); + if (mExpandedBubble.getExpandedView().getTaskView() != null) { + mExpandedBubble.getExpandedView().getTaskView().setObscuredTouchRect(mShowingManage + ? new Rect(0, 0, getWidth(), getHeight()) + : null); + } final boolean isLtr = getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_LTR; 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 7ce9014fc9ba..57a9dd2ec6cc 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 @@ -143,14 +143,14 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor @ImeAnimationFlags public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop, boolean imeShouldShow, boolean imeIsFloating, SurfaceControl.Transaction t) { - mHiddenTop = hiddenTop; - mShownTop = shownTop; - mTargetShown = imeShouldShow; if (!isDividerVisible()) { return 0; } - final boolean splitIsVisible = !getView().isHidden(); + mHiddenTop = hiddenTop; + mShownTop = shownTop; + mTargetShown = imeShouldShow; mSecondaryHasFocus = getSecondaryHasFocus(displayId); + final boolean splitIsVisible = !getView().isHidden(); final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus && !imeIsFloating && !getLayout().mDisplayLayout.isLandscape() && !mSplits.mSplitScreenController.isMinimized(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java index 725f87d93e4e..580861cf4974 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java @@ -121,6 +121,19 @@ public class PhonePipMenuController implements PipMenuController { } }; + private final float[] mTmpValues = new float[9]; + private final Runnable mUpdateEmbeddedMatrix = () -> { + if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) { + return; + } + mMoveTransform.getValues(mTmpValues); + try { + mPipMenuView.getViewRootImpl().getAccessibilityEmbeddedConnection() + .setScreenMatrix(mTmpValues); + } catch (RemoteException e) { + } + }; + public PhonePipMenuController(Context context, PipMediaController mediaController, SystemWindows systemWindows, ShellExecutor mainExecutor, Handler mainHandler) { @@ -306,6 +319,11 @@ public class PhonePipMenuController implements PipMenuController { } else { mApplier.scheduleApply(params); } + + if (mPipMenuView.getViewRootImpl() != null) { + mPipMenuView.getHandler().removeCallbacks(mUpdateEmbeddedMatrix); + mPipMenuView.getHandler().post(mUpdateEmbeddedMatrix); + } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java index 0d64407f649f..8ab405bca7db 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java @@ -32,7 +32,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; -import android.annotation.Nullable; import android.app.PendingIntent.CanceledException; import android.app.RemoteAction; import android.content.ComponentName; @@ -52,10 +51,8 @@ import android.util.Size; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; -import android.view.SurfaceControl; import android.view.View; import android.view.ViewGroup; -import android.view.ViewRootImpl; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; @@ -198,6 +195,11 @@ public class PipMenuView extends FrameLayout { } @Override + public boolean shouldDelayChildPressedState() { + return true; + } + + @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (!mAllowTouches) { return false; @@ -287,18 +289,6 @@ public class PipMenuView extends FrameLayout { } } - @Nullable SurfaceControl getWindowSurfaceControl() { - final ViewRootImpl root = getViewRootImpl(); - if (root == null) { - return null; - } - final SurfaceControl out = root.getSurfaceControl(); - if (out != null && out.isValid()) { - return out; - } - return null; - } - /** * Different from {@link #hideMenu()}, this function does not try to finish this menu activity * and instead, it fades out the controls by setting the alpha to 0 directly without menu @@ -398,8 +388,20 @@ public class PipMenuView extends FrameLayout { return true; }); + // Update the expand button only if it should show with the menu + expandContainer.setVisibility(mMenuState == MENU_STATE_FULL + ? View.VISIBLE + : View.INVISIBLE); + + FrameLayout.LayoutParams expandedLp = + (FrameLayout.LayoutParams) expandContainer.getLayoutParams(); if (mActions.isEmpty() || mMenuState == MENU_STATE_CLOSE || mMenuState == MENU_STATE_NONE) { actionsContainer.setVisibility(View.INVISIBLE); + + // Update the expand container margin to adjust the center of the expand button to + // account for the existence of the action container + expandedLp.topMargin = 0; + expandedLp.bottomMargin = 0; } else { actionsContainer.setVisibility(View.VISIBLE); if (mActionsGroup != null) { @@ -455,14 +457,12 @@ public class PipMenuView extends FrameLayout { // Update the expand container margin to adjust the center of the expand button to // account for the existence of the action container - FrameLayout.LayoutParams expandedLp = - (FrameLayout.LayoutParams) expandContainer.getLayoutParams(); expandedLp.topMargin = getResources().getDimensionPixelSize( R.dimen.pip_action_padding); expandedLp.bottomMargin = getResources().getDimensionPixelSize( R.dimen.pip_expand_container_edge_margin); - expandContainer.requestLayout(); } + expandContainer.requestLayout(); } private void notifyMenuStateChange(int menuState, boolean resize, Runnable callback) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java new file mode 100644 index 000000000000..5bc2afd11fe8 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.startingsurface; + +import static android.view.View.GONE; + +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.graphics.BlendMode; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.RadialGradient; +import android.graphics.Rect; +import android.graphics.Shader; +import android.util.Slog; +import android.view.SurfaceControl; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.view.animation.AnimationSet; +import android.view.animation.Interpolator; +import android.view.animation.PathInterpolator; +import android.view.animation.Transformation; +import android.view.animation.TranslateYAnimation; +import android.window.SplashScreenView; + +import com.android.wm.shell.common.TransactionPool; + +/** + * Default animation for exiting the splash screen window. + * @hide + */ +public class SplashScreenExitAnimation implements Animator.AnimatorListener { + private static final boolean DEBUG_EXIT_ANIMATION = false; + private static final boolean DEBUG_EXIT_ANIMATION_BLEND = false; + private static final String TAG = StartingSurfaceDrawer.TAG; + + private static final Interpolator ICON_EXIT_INTERPOLATOR = new PathInterpolator(1f, 0f, 1f, 1f); + private static final Interpolator APP_EXIT_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f); + + private static final int EXTRA_REVEAL_DELAY = 133; + private final Matrix mTmpTransform = new Matrix(); + private final float[] mTmpFloat9 = new float[9]; + private SurfaceControl mFirstWindowSurface; + private final Rect mFirstWindowFrame = new Rect(); + private final SplashScreenView mSplashScreenView; + private final int mMainWindowShiftLength; + private final int mIconShiftLength; + private final int mAppDuration; + private final int mIconDuration; + private final TransactionPool mTransactionPool; + + private ValueAnimator mMainAnimator; + private Animation mShiftUpAnimation; + private AnimationSet mIconAnimationSet; + private Runnable mFinishCallback; + + SplashScreenExitAnimation(SplashScreenView view, SurfaceControl leash, Rect frame, + int appDuration, int iconDuration, int mainWindowShiftLength, int iconShiftLength, + TransactionPool pool, Runnable handleFinish) { + mSplashScreenView = view; + mFirstWindowSurface = leash; + if (frame != null) { + mFirstWindowFrame.set(frame); + } + mAppDuration = appDuration; + mIconDuration = iconDuration; + mMainWindowShiftLength = mainWindowShiftLength; + mIconShiftLength = iconShiftLength; + mFinishCallback = handleFinish; + mTransactionPool = pool; + } + + void prepareAnimations() { + prepareRevealAnimation(); + prepareShiftAnimation(); + } + + void startAnimations() { + if (mIconAnimationSet != null) { + mIconAnimationSet.start(); + } + if (mMainAnimator != null) { + mMainAnimator.start(); + } + if (mShiftUpAnimation != null) { + mShiftUpAnimation.start(); + } + } + + // reveal splash screen, shift up main window + private void prepareRevealAnimation() { + // splash screen + mMainAnimator = ValueAnimator.ofFloat(0f, 1f); + mMainAnimator.setDuration(mAppDuration); + mMainAnimator.setInterpolator(APP_EXIT_INTERPOLATOR); + mMainAnimator.addListener(this); + + final int startDelay = mIconDuration + EXTRA_REVEAL_DELAY; + final float transparentRatio = 0.95f; + final int globalHeight = mSplashScreenView.getHeight(); + final int verticalCircleCenter = 0; + final int finalVerticalLength = globalHeight - verticalCircleCenter; + final int halfWidth = mSplashScreenView.getWidth() / 2; + final int endRadius = (int) (0.5 + (1f / transparentRatio * (int) + Math.sqrt(finalVerticalLength * finalVerticalLength + halfWidth * halfWidth))); + final RadialVanishAnimation radialVanishAnimation = new RadialVanishAnimation( + mSplashScreenView, mMainAnimator); + radialVanishAnimation.setCircleCenter(halfWidth, verticalCircleCenter); + radialVanishAnimation.setRadius(0/* initRadius */, endRadius); + final int[] colors = {Color.TRANSPARENT, Color.TRANSPARENT, Color.WHITE}; + final float[] stops = {0f, transparentRatio, 1f}; + radialVanishAnimation.setRadialPaintParam(colors, stops); + radialVanishAnimation.setReady(); + mMainAnimator.setStartDelay(startDelay); + + if (mFirstWindowSurface != null) { + // shift up main window + View occludeHoleView = new View(mSplashScreenView.getContext()); + if (DEBUG_EXIT_ANIMATION_BLEND) { + occludeHoleView.setBackgroundColor(Color.BLUE); + } else { + occludeHoleView.setBackgroundColor(mSplashScreenView.getInitBackgroundColor()); + } + final ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( + WindowManager.LayoutParams.MATCH_PARENT, mMainWindowShiftLength); + mSplashScreenView.addView(occludeHoleView, params); + + mShiftUpAnimation = new ShiftUpAnimation(0, -mMainWindowShiftLength); + mShiftUpAnimation.setDuration(mAppDuration); + mShiftUpAnimation.setInterpolator(APP_EXIT_INTERPOLATOR); + mShiftUpAnimation.setStartOffset(startDelay); + + occludeHoleView.setAnimation(mShiftUpAnimation); + } + } + + // shift down icon and branding view + private void prepareShiftAnimation() { + final View iconView = mSplashScreenView.getIconView(); + if (iconView == null) { + return; + } + if (mIconShiftLength > 0) { + mIconAnimationSet = new AnimationSet(true /* shareInterpolator */); + if (DEBUG_EXIT_ANIMATION) { + Slog.v(TAG, "first exit animation, shift length: " + mIconShiftLength); + } + mIconAnimationSet.addAnimation(new TranslateYAnimation(0, mIconShiftLength)); + mIconAnimationSet.addAnimation(new AlphaAnimation(1, 0)); + mIconAnimationSet.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + + } + + @Override + public void onAnimationEnd(Animation animation) { + if (DEBUG_EXIT_ANIMATION) { + Slog.v(TAG, "first exit animation finished"); + } + iconView.post(() -> iconView.setVisibility(GONE)); + } + + @Override + public void onAnimationRepeat(Animation animation) { + // ignore + } + }); + mIconAnimationSet.setDuration(mIconDuration); + mIconAnimationSet.setInterpolator(ICON_EXIT_INTERPOLATOR); + iconView.setAnimation(mIconAnimationSet); + final View brandingView = mSplashScreenView.getBrandingView(); + if (brandingView != null) { + brandingView.setAnimation(mIconAnimationSet); + } + } + } + + private static class RadialVanishAnimation extends View { + private SplashScreenView mView; + private int mInitRadius; + private int mFinishRadius; + private boolean mReady; + + private final Point mCircleCenter = new Point(); + private final Matrix mVanishMatrix = new Matrix(); + private final Paint mVanishPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + RadialVanishAnimation(SplashScreenView target, ValueAnimator animator) { + super(target.getContext()); + mView = target; + animator.addUpdateListener((animation) -> { + if (mVanishPaint.getShader() == null) { + return; + } + final float value = (float) animation.getAnimatedValue(); + final float scale = (mFinishRadius - mInitRadius) * value + mInitRadius; + mVanishMatrix.setScale(scale, scale); + mVanishMatrix.postTranslate(mCircleCenter.x, mCircleCenter.y); + mVanishPaint.getShader().setLocalMatrix(mVanishMatrix); + mView.postInvalidate(); + }); + mView.addView(this); + } + + void setRadius(int initRadius, int finishRadius) { + if (DEBUG_EXIT_ANIMATION) { + Slog.v(TAG, "RadialVanishAnimation setRadius init: " + initRadius + + " final " + finishRadius); + } + mInitRadius = initRadius; + mFinishRadius = finishRadius; + } + + void setCircleCenter(int x, int y) { + if (DEBUG_EXIT_ANIMATION) { + Slog.v(TAG, "RadialVanishAnimation setCircleCenter x: " + x + " y " + y); + } + mCircleCenter.set(x, y); + } + + void setRadialPaintParam(int[] colors, float[] stops) { + // setup gradient shader + final RadialGradient rShader = + new RadialGradient(0, 0, 1, colors, stops, Shader.TileMode.CLAMP); + mVanishPaint.setShader(rShader); + if (!DEBUG_EXIT_ANIMATION_BLEND) { + mVanishPaint.setBlendMode(BlendMode.MODULATE); + } + } + + void setReady() { + mReady = true; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (mReady) { + canvas.drawRect(0, 0, mView.getWidth(), mView.getHeight(), mVanishPaint); + } + } + } + + private final class ShiftUpAnimation extends TranslateYAnimation { + ShiftUpAnimation(float fromYDelta, float toYDelta) { + super(fromYDelta, toYDelta); + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + super.applyTransformation(interpolatedTime, t); + + if (mFirstWindowSurface == null) { + return; + } + mTmpTransform.set(t.getMatrix()); + final SurfaceControl.Transaction tx = mTransactionPool.acquire(); + mTmpTransform.postTranslate(mFirstWindowFrame.left, + mFirstWindowFrame.top + mMainWindowShiftLength); + tx.setMatrix(mFirstWindowSurface, mTmpTransform, mTmpFloat9); + // TODO set the vsyncId to ensure the transaction doesn't get applied too early. + // Additionally, do you want to have this synchronized with your view animations? + // If so, you'll need to use SyncRtSurfaceTransactionApplier + tx.apply(); + mTransactionPool.release(tx); + } + } + + private void reset() { + if (DEBUG_EXIT_ANIMATION) { + Slog.v(TAG, "vanish animation finished"); + } + mSplashScreenView.post(() -> { + mSplashScreenView.setVisibility(GONE); + if (mFinishCallback != null) { + mFinishCallback.run(); + mFinishCallback = null; + } + }); + if (mFirstWindowSurface != null) { + final SurfaceControl.Transaction tx = mTransactionPool.acquire(); + tx.setWindowCrop(mFirstWindowSurface, null); + tx.apply(); + mFirstWindowSurface.release(); + mFirstWindowSurface = null; + } + } + + @Override + public void onAnimationStart(Animator animation) { + // ignore + } + + @Override + public void onAnimationEnd(Animator animation) { + reset(); + } + + @Override + public void onAnimationCancel(Animator animation) { + reset(); + } + + @Override + public void onAnimationRepeat(Animator animation) { + // ignore + } +} 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 2973b5080ae6..3f9c2717731a 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 @@ -31,12 +31,14 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.os.Build; import android.util.Slog; +import android.view.SurfaceControl; import android.window.SplashScreenView; import com.android.internal.R; import com.android.internal.graphics.palette.Palette; import com.android.internal.graphics.palette.Quantizer; import com.android.internal.graphics.palette.VariationalKMeansQuantizer; +import com.android.wm.shell.common.TransactionPool; import java.util.List; @@ -56,15 +58,25 @@ public class SplashscreenContentDrawer { // 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 final Context mContext; - private final int mMaxIconAnimationDuration; + private final int mMaxAnimatableIconDuration; private int mIconSize; private int mBrandingImageWidth; private int mBrandingImageHeight; - - SplashscreenContentDrawer(Context context, int maxIconAnimationDuration) { + private final int mAppRevealDuration; + private final int mIconExitDuration; + private int mMainWindowShiftLength; + private int mIconNormalExitDistance; + private int mIconEarlyExitDistance; + private final TransactionPool mTransactionPool; + + SplashscreenContentDrawer(Context context, int maxAnimatableIconDuration, + int iconExitAnimDuration, int appRevealAnimDuration, TransactionPool pool) { mContext = context; - mMaxIconAnimationDuration = maxIconAnimationDuration; + mMaxAnimatableIconDuration = maxAnimatableIconDuration; + mAppRevealDuration = appRevealAnimDuration; + mIconExitDuration = iconExitAnimDuration; + mTransactionPool = pool; } private void updateDensity() { @@ -74,6 +86,12 @@ public class SplashscreenContentDrawer { com.android.wm.shell.R.dimen.starting_surface_brand_image_width); mBrandingImageHeight = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.starting_surface_brand_image_height); + mMainWindowShiftLength = mContext.getResources().getDimensionPixelSize( + com.android.wm.shell.R.dimen.starting_surface_exit_animation_window_shift_length); + mIconNormalExitDistance = mContext.getResources().getDimensionPixelSize( + com.android.wm.shell.R.dimen.starting_surface_normal_exit_icon_distance); + mIconEarlyExitDistance = mContext.getResources().getDimensionPixelSize( + com.android.wm.shell.R.dimen.starting_surface_early_exit_icon_distance); } private int getSystemBGColor() { @@ -119,7 +137,7 @@ public class SplashscreenContentDrawer { if (attrs.mReplaceIcon != null) { iconDrawable = attrs.mReplaceIcon; animationDuration = Math.max(0, - Math.min(attrs.mAnimationDuration, mMaxIconAnimationDuration)); + Math.min(attrs.mAnimationDuration, mMaxAnimatableIconDuration)); } else { iconDrawable = iconRes != 0 ? context.getDrawable(iconRes) : context.getPackageManager().getDefaultActivityIcon(); @@ -439,8 +457,8 @@ public class SplashscreenContentDrawer { } /** - * For ColorDrawable only. - * There will be only one color so don't spend too much resource for it. + * For ColorDrawable only. There will be only one color so don't spend too much resource for + * it. */ private static class SingleColorTester implements ColorTester { private final ColorDrawable mColorDrawable; @@ -472,9 +490,8 @@ public class SplashscreenContentDrawer { } /** - * For any other Drawable except ColorDrawable. - * This will use the Palette API to check the color information and use a quantizer to - * filter out transparent colors when needed. + * For any other Drawable except ColorDrawable. This will use the Palette API to check the + * color information and use a quantizer to filter out transparent colors when needed. */ private static class ComplexDrawableTester implements ColorTester { private static final int MAX_BITMAP_SIZE = 40; @@ -593,4 +610,17 @@ public class SplashscreenContentDrawer { } } } + + /** + * Create and play the default exit animation for splash screen view. + */ + void applyExitAnimation(SplashScreenView view, SurfaceControl leash, + Rect frame, boolean isEarlyExit, Runnable finishCallback) { + final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(view, leash, + frame, mAppRevealDuration, mIconExitDuration, mMainWindowShiftLength, + isEarlyExit ? mIconEarlyExitDistance : mIconNormalExitDistance, mTransactionPool, + finishCallback); + animation.prepareAnimations(); + animation.startAnimations(); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java index a594a9f31dde..f258286f2d17 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java @@ -16,7 +16,9 @@ package com.android.wm.shell.startingsurface; +import android.graphics.Rect; import android.os.IBinder; +import android.view.SurfaceControl; import android.window.StartingWindowInfo; import java.util.function.BiConsumer; @@ -31,7 +33,8 @@ public interface StartingSurface { /** * Called when the content of a task is ready to show, starting window can be removed. */ - void removeStartingWindow(int taskId); + void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation); /** * Called when the Task wants to copy the splash screen. * @param taskId diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java index 2d1d65b87718..14fbaacb9613 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 @@ -29,14 +29,18 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; import android.hardware.display.DisplayManager; import android.os.IBinder; +import android.os.SystemClock; import android.util.Slog; import android.util.SparseArray; -import android.view.Choreographer; import android.view.Display; +import android.view.SurfaceControl; import android.view.View; -import android.view.Window; import android.view.WindowManager; import android.window.SplashScreenView; import android.window.SplashScreenView.SplashScreenViewParcelable; @@ -46,6 +50,7 @@ import android.window.TaskSnapshot; import com.android.internal.R; import com.android.internal.policy.PhoneWindow; import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.TransactionPool; import java.util.function.Consumer; @@ -62,23 +67,23 @@ public class StartingSurfaceDrawer { private final DisplayManager mDisplayManager; private final ShellExecutor mSplashScreenExecutor; private final SplashscreenContentDrawer mSplashscreenContentDrawer; - protected Choreographer mChoreographer; // TODO(b/131727939) remove this when clearing ActivityRecord private static final int REMOVE_WHEN_TIMEOUT = 2000; - public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor) { + public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor, + TransactionPool pool) { mContext = context; mDisplayManager = mContext.getSystemService(DisplayManager.class); mSplashScreenExecutor = splashScreenExecutor; - final int maxIconAnimDuration = context.getResources().getInteger( + final int maxAnimatableIconDuration = context.getResources().getInteger( com.android.wm.shell.R.integer.max_starting_window_intro_icon_anim_duration); - mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, maxIconAnimDuration); - mSplashScreenExecutor.execute(this::initChoreographer); - } - - protected void initChoreographer() { - mChoreographer = Choreographer.getInstance(); + 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); } private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>(); @@ -195,6 +200,7 @@ public class StartingSurfaceDrawer { } final PhoneWindow win = new PhoneWindow(context); + win.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); win.setIsStartingWindow(true); CharSequence label = context.getResources().getText(labelRes, null); @@ -211,7 +217,7 @@ public class StartingSurfaceDrawer { // the keyguard is being hidden. This is okay because starting windows never show // secret information. // TODO(b/113840485): Occluded may not only happen on default display - if (displayId == DEFAULT_DISPLAY) { + if (displayId == DEFAULT_DISPLAY && windowInfo.isKeyguardOccluded) { windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; } @@ -247,6 +253,7 @@ public class StartingSurfaceDrawer { // Setting as trusted overlay to let touches pass through. This is safe because this // window is controlled by the system. params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; + params.format = PixelFormat.RGBA_8888; final Resources res = context.getResources(); final boolean supportsScreen = res != null && (res.getCompatibilityInfo() != null @@ -257,98 +264,25 @@ public class StartingSurfaceDrawer { params.setTitle("Splash Screen " + activityInfo.packageName); - // TODO(b/173975965) If the target activity doesn't request FLAG_HARDWARE_ACCELERATED, we - // cannot replace the content view after first view was drawn, sounds like an issue. - new AddSplashScreenViewRunnable(taskInfo.taskId, win, context, appToken, params, iconRes, - splashscreenContentResId[0], enableHardAccelerated).run(); - } - - private class AddSplashScreenViewRunnable implements Runnable { - private final int mTaskId; - private final Window mWin; - private final IBinder mAppToken; - private final WindowManager.LayoutParams mLayoutParams; - private final Context mContext; - private final int mIconRes; - private final int mSplashscreenContentResId; - private final boolean mReplaceSplashScreenView; - private int mSequence; - - AddSplashScreenViewRunnable(int taskId, Window window, Context context, - IBinder appToken, WindowManager.LayoutParams params, int iconRes, - int splashscreenContentResId, boolean replaceSplashScreenView) { - mTaskId = taskId; - mWin = window; - mAppToken = appToken; - mContext = context; - mLayoutParams = params; - mIconRes = iconRes; - mSplashscreenContentResId = splashscreenContentResId; - mReplaceSplashScreenView = replaceSplashScreenView; - } - - private void createInitialView() { - View tempView = new View(mContext); - mWin.setContentView(tempView); - mSequence++; - final View view = mWin.getDecorView(); - final WindowManager wm = mContext.getSystemService(WindowManager.class); - if (postAddWindow(mTaskId, mAppToken, view, wm, mLayoutParams)) { - mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, this, null); - } - } - - private SplashScreenView replaceRealView() { - final SplashScreenView sView = - mSplashscreenContentDrawer.makeSplashScreenContentView(mContext, - mIconRes, mSplashscreenContentResId); - mWin.setContentView(sView); - sView.cacheRootWindow(mWin); - return sView; - } - - private SplashScreenView initiateOnce() { - final SplashScreenView sView = - mSplashscreenContentDrawer.makeSplashScreenContentView(mContext, mIconRes, - mSplashscreenContentResId); - final View view = mWin.getDecorView(); + // TODO(b/173975965) tracking performance + final int taskId = taskInfo.taskId; + SplashScreenView sView = null; + try { + sView = mSplashscreenContentDrawer.makeSplashScreenContentView(context, iconRes, + splashscreenContentResId[0]); + final View view = win.getDecorView(); final WindowManager wm = mContext.getSystemService(WindowManager.class); - if (postAddWindow(mTaskId, mAppToken, view, wm, mLayoutParams)) { - mWin.setContentView(sView); - sView.cacheRootWindow(mWin); - } - return sView; - } - - @Override - public void run() { - SplashScreenView view = null; - boolean setRecord = false; - try { - if (mReplaceSplashScreenView) { - // Tricky way to make animation start faster... create the real content after - // first window drawn. The first empty window won't been see because wm will - // still need to wait for transition ready. - if (mSequence == 0) { - createInitialView(); - } else if (mSequence == 1) { - setRecord = true; - view = replaceRealView(); - } - } else { - setRecord = true; - view = initiateOnce(); - } - } catch (RuntimeException e) { - // don't crash if something else bad happens, for example a - // failure loading resources because we are loading from an app - // on external storage that has been unmounted. - Slog.w(TAG, " failed creating starting window", e); - } finally { - if (setRecord) { - setSplashScreenRecord(mTaskId, view); - } + if (postAddWindow(taskId, appToken, view, wm, params)) { + win.setContentView(sView); + sView.cacheRootWindow(win); } + } catch (RuntimeException e) { + // don't crash if something else bad happens, for example a + // failure loading resources because we are loading from an app + // on external storage that has been unmounted. + Slog.w(TAG, " failed creating starting window", e); + } finally { + setSplashScreenRecord(taskId, sView); } } @@ -359,8 +293,10 @@ public class StartingSurfaceDrawer { TaskSnapshot snapshot) { final int taskId = startingWindowInfo.taskInfo.taskId; final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken, - snapshot, mSplashScreenExecutor, () -> removeWindowSynced(taskId)); - mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT); + snapshot, mSplashScreenExecutor, + () -> removeWindowNoAnimate(taskId)); + mSplashScreenExecutor.executeDelayed(() -> removeWindowNoAnimate(taskId), + REMOVE_WHEN_TIMEOUT); final StartingWindowRecord tView = new StartingWindowRecord(null/* decorView */, surface); mStartingWindowRecords.put(taskId, tView); @@ -369,11 +305,12 @@ public class StartingSurfaceDrawer { /** * Called when the content of a task is ready to show, starting window can be removed. */ - public void removeStartingWindow(int taskId) { + public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { Slog.d(TAG, "Task start finish, remove starting surface for task " + taskId); } - removeWindowSynced(taskId); + removeWindowSynced(taskId, leash, frame, playRevealAnimation); } /** @@ -383,13 +320,6 @@ public class StartingSurfaceDrawer { public void copySplashScreenView(int taskId) { final StartingWindowRecord preView = mStartingWindowRecords.get(taskId); SplashScreenViewParcelable parcelable; - if (preView != null) { - if (preView.isWaitForContent()) { - mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, - () -> copySplashScreenView(taskId), null); - return; - } - } if (preView != null && preView.mContentView != null && preView.mContentView.isCopyable()) { parcelable = new SplashScreenViewParcelable(preView.mContentView); @@ -413,12 +343,6 @@ public class StartingSurfaceDrawer { Slog.w(TAG, appToken + " already running, starting window not displayed. " + e.getMessage()); shouldSaveView = false; - } catch (RuntimeException e) { - // don't crash if something else bad happens, for example a - // failure loading resources because we are loading from an app - // on external storage that has been unmounted. - Slog.w(TAG, appToken + " failed creating starting window", e); - shouldSaveView = false; } finally { if (view != null && view.getParent() == null) { Slog.w(TAG, "view not successfully added to wm, removing view"); @@ -427,9 +351,9 @@ public class StartingSurfaceDrawer { } } if (shouldSaveView) { - removeWindowSynced(taskId); - mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId), - REMOVE_WHEN_TIMEOUT); + removeWindowNoAnimate(taskId); + mSplashScreenExecutor.executeDelayed( + () -> removeWindowNoAnimate(taskId), REMOVE_WHEN_TIMEOUT); saveSplashScreenRecord(taskId, view); } return shouldSaveView; @@ -449,24 +373,30 @@ public class StartingSurfaceDrawer { } } - protected void removeWindowSynced(int taskId) { + private void removeWindowNoAnimate(int taskId) { + removeWindowSynced(taskId, null, null, false); + } + + protected void removeWindowSynced(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { final StartingWindowRecord record = mStartingWindowRecords.get(taskId); if (record != null) { - if (record.isWaitForContent()) { - if (DEBUG_SPLASH_SCREEN) { - Slog.v(TAG, "splash screen window haven't been draw yet"); - } - mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, - () -> removeWindowSynced(taskId), null); - return; - } if (record.mDecorView != null) { if (DEBUG_SPLASH_SCREEN) { Slog.v(TAG, "Removing splash screen window for task: " + taskId); } - final WindowManager wm = record.mDecorView.getContext() - .getSystemService(WindowManager.class); - wm.removeView(record.mDecorView); + if (record.mContentView != null) { + final HandleExitFinish exitFinish = new HandleExitFinish(record.mDecorView); + if (leash != null || playRevealAnimation) { + mSplashscreenContentDrawer.applyExitAnimation(record.mContentView, + leash, frame, record.isEarlyExit(), exitFinish); + mSplashScreenExecutor.executeDelayed(exitFinish, REMOVE_WHEN_TIMEOUT); + } else { + // the SplashScreenView has been copied to client, skip default exit + // animation + exitFinish.run(); + } + } } if (record.mTaskSnapshotWindow != null) { if (DEBUG_TASK_SNAPSHOT) { @@ -478,6 +408,26 @@ public class StartingSurfaceDrawer { } } + private static class HandleExitFinish implements Runnable { + private View mDecorView; + + HandleExitFinish(View decorView) { + mDecorView = decorView; + } + + @Override + public void run() { + if (mDecorView == null) { + return; + } + final WindowManager wm = mDecorView.getContext().getSystemService(WindowManager.class); + if (wm != null) { + wm.removeView(mDecorView); + } + mDecorView = null; + } + } + private void getWindowResFromContext(Context ctx, Consumer<TypedArray> consumer) { final TypedArray a = ctx.obtainStyledAttributes(R.styleable.Window); consumer.accept(a); @@ -488,10 +438,12 @@ public class StartingSurfaceDrawer { * Record the view or surface for a starting window. */ private static class StartingWindowRecord { + private static final long EARLY_START_MINIMUM_TIME_MS = 250; private final View mDecorView; private final TaskSnapshotWindow mTaskSnapshotWindow; private SplashScreenView mContentView; private boolean mSetSplashScreen; + private long mContentCreateTime; StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) { mDecorView = decorView; @@ -503,11 +455,12 @@ public class StartingSurfaceDrawer { return; } mContentView = splashScreenView; + mContentCreateTime = SystemClock.uptimeMillis(); mSetSplashScreen = true; } - private boolean isWaitForContent() { - return mDecorView != null && !mSetSplashScreen; + boolean isEarlyExit() { + return SystemClock.uptimeMillis() - mContentCreateTime < EARLY_START_MINIMUM_TIME_MS; } } } 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 5eb7071fbd63..a694e525a761 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 @@ -28,14 +28,17 @@ import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; import android.content.Context; +import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; +import android.view.SurfaceControl; import android.window.StartingWindowInfo; import android.window.TaskOrganizer; import android.window.TaskSnapshot; import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.TransactionPool; import java.util.function.BiConsumer; @@ -67,8 +70,16 @@ public class StartingWindowController { private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl(); private final ShellExecutor mSplashScreenExecutor; + // For Car Launcher public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) { - mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor); + mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, + new TransactionPool()); + mSplashScreenExecutor = splashScreenExecutor; + } + + public StartingWindowController(Context context, ShellExecutor splashScreenExecutor, + TransactionPool pool) { + mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool); mSplashScreenExecutor = splashScreenExecutor; } @@ -112,7 +123,8 @@ public class StartingWindowController { + " allowTaskSnapshot " + allowTaskSnapshot + " activityCreated " + activityCreated); } - if (newTask || !processRunning || (taskSwitch && !activityCreated)) { + if ((newTask || !processRunning || (taskSwitch && !activityCreated)) + && windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) { return STARTING_WINDOW_TYPE_SPLASH_SCREEN; } if (taskSwitch && allowTaskSnapshot) { @@ -198,8 +210,9 @@ public class StartingWindowController { /** * Called when the content of a task is ready to show, starting window can be removed. */ - void removeStartingWindow(int taskId) { - mStartingSurfaceDrawer.removeStartingWindow(taskId); + void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { + mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation); } private class StartingSurfaceImpl implements StartingSurface { @@ -211,9 +224,11 @@ public class StartingWindowController { } @Override - public void removeStartingWindow(int taskId) { + public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { mSplashScreenExecutor.execute(() -> - StartingWindowController.this.removeStartingWindow(taskId)); + StartingWindowController.this.removeStartingWindow(taskId, leash, frame, + playRevealAnimation)); } @Override diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml index f06d57c6c789..ad4ccc0288ad 100644 --- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml +++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml @@ -11,6 +11,8 @@ <option name="force-skip-system-props" value="true" /> <!-- set WM tracing verbose level to all --> <option name="run-command" value="cmd window tracing level all" /> + <!-- set WM tracing to frame (avoid incomplete states) --> + <option name="run-command" value="cmd window tracing frame" /> <!-- restart launcher to activate TAPL --> <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" /> </target_preparer> diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt index ecc066be734f..5a96a7c8cbd9 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt @@ -17,7 +17,6 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.graphics.Point import android.media.session.MediaController import android.media.session.MediaSessionManager import android.os.SystemClock @@ -135,11 +134,8 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( expandPipWindow(wmHelper) val exitPipObject = uiDevice.findObject(By.res(SYSTEMUI_PACKAGE, "dismiss")) requireNotNull(exitPipObject) { "PIP window dismiss button not found" } - val coordinatesInWindow = exitPipObject.visibleBounds - val windowOffset = wmHelper.getWindowRegion(component).bounds - val newCoordinates = Point(windowOffset.left + coordinatesInWindow.centerX(), - windowOffset.top + coordinatesInWindow.centerY()) - uiDevice.click(newCoordinates.x, newCoordinates.y) + val dismissButtonBounds = exitPipObject.visibleBounds + uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY()) } // Wait for animation to complete. diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java index a531ef58725d..207db9e80511 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package unittest.src.com.android.wm.shell.startingsurface; +package com.android.wm.shell.startingsurface; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -33,11 +33,12 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.testing.TestableContext; -import android.view.Choreographer; +import android.view.SurfaceControl; import android.view.View; import android.view.WindowManager; import android.view.WindowMetrics; @@ -49,7 +50,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.wm.shell.common.HandlerExecutor; import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.startingsurface.StartingSurfaceDrawer; +import com.android.wm.shell.common.TransactionPool; import org.junit.Before; import org.junit.Test; @@ -68,7 +69,7 @@ public class StartingSurfaceDrawerTests { @Mock private WindowManager mMockWindowManager; @Mock - private static Choreographer sFakeChoreographer; + private TransactionPool mTransactionPool; TestStartingSurfaceDrawer mStartingSurfaceDrawer; @@ -76,13 +77,9 @@ public class StartingSurfaceDrawerTests { int mAddWindowForTask = 0; int mViewThemeResId; - TestStartingSurfaceDrawer(Context context, ShellExecutor executor) { - super(context, executor); - } - - @Override - protected void initChoreographer() { - mChoreographer = sFakeChoreographer; + TestStartingSurfaceDrawer(Context context, ShellExecutor animExecutor, + TransactionPool pool) { + super(context, animExecutor, pool); } @Override @@ -95,7 +92,8 @@ public class StartingSurfaceDrawerTests { } @Override - protected void removeWindowSynced(int taskId) { + protected void removeWindowSynced(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { // listen for removeView if (mAddWindowForTask == taskId) { mAddWindowForTask = 0; @@ -123,7 +121,8 @@ public class StartingSurfaceDrawerTests { doNothing().when(mMockWindowManager).addView(any(), any()); mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(context, - new HandlerExecutor(new Handler(Looper.getMainLooper())))); + new HandlerExecutor(new Handler(Looper.getMainLooper())), + mTransactionPool)); } @Test @@ -137,9 +136,9 @@ public class StartingSurfaceDrawerTests { verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any()); assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId); - mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId); + mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId, null, null, false); waitHandlerIdle(mainLoop); - verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId)); + verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId), any(), any(), eq(false)); assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, 0); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java index 27e5f51d88b8..b908df20d3c0 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package unittest.src.com.android.wm.shell.startingsurface; +package com.android.wm.shell.startingsurface; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; @@ -48,7 +48,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.wm.shell.TestShellExecutor; -import com.android.wm.shell.startingsurface.TaskSnapshotWindow; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index aba0f1b47673..63b831de5da1 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -97,8 +97,8 @@ cc_library { "libincfs", "libutils", "libz", - "libziparchive", ], + static_libs: ["libziparchive_for_incfs"], static: { enabled: false, }, diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index d663c52b2c08..607ef72df96a 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -388,11 +388,10 @@ cc_defaults { "liblog", "libminikin", "libz", - "libziparchive", "libjpeg", ], - static_libs: ["libnativehelper_lazy"], + static_libs: ["libnativehelper_lazy", "libziparchive_for_incfs"], target: { android: { diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 9793300b406d..800c58095041 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -576,6 +576,7 @@ void CanvasContext::draw() { if (requireSwap) { if (mExpectSurfaceStats) { + reportMetricsWithPresentTime(); std::lock_guard lock(mLast4FrameInfosMutex); std::pair<FrameInfo*, int64_t>& next = mLast4FrameInfos.next(); next.first = mCurrentFrameInfo; @@ -656,8 +657,6 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* cont } } - instance->reportMetricsWithPresentTime(); - if (frameInfo != nullptr) { if (gpuCompleteTime == -1) { gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted); diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h index 09c6a4fdf50d..a8f2d9a28d67 100644 --- a/libs/hwui/utils/PaintUtils.h +++ b/libs/hwui/utils/PaintUtils.h @@ -52,18 +52,10 @@ public: return mode == SkBlendMode::kSrcOver || mode == SkBlendMode::kSrc; } - static bool isBlendedShader(const SkShader* shader) { - if (shader == nullptr) { - return false; - } - return !shader->isOpaque(); - } + static bool isBlendedShader(const SkShader* shader) { return shader && !shader->isOpaque(); } static bool isBlendedColorFilter(const SkColorFilter* filter) { - if (filter == nullptr) { - return false; - } - return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0; + return filter && !filter->isAlphaUnchanged(); } static inline SkBlendMode getBlendModeDirect(const SkPaint* paint) { diff --git a/media/Android.bp b/media/Android.bp index 9268b22a929a..a66236e6f4ea 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -27,6 +27,9 @@ aidl_interface { aidl_interface { name: "media_permission-aidl", unstable: true, + host_supported: true, + vendor_available: true, + double_loadable: true, local_include_dir: "aidl", srcs: [ "aidl/android/media/permission/Identity.aidl", diff --git a/media/aidl/android/media/permission/Identity.aidl b/media/aidl/android/media/permission/Identity.aidl index 361497d59ea9..36389047cee8 100644 --- a/media/aidl/android/media/permission/Identity.aidl +++ b/media/aidl/android/media/permission/Identity.aidl @@ -22,11 +22,11 @@ package android.media.permission; */ parcelable Identity { /** Linux user ID. */ - int uid; + int uid = -1; /** Linux process ID. */ - int pid; + int pid = -1; /** Package name. If null, the first package owned by the given uid will be assumed. */ - @nullable String packageName; + @nullable @utf8InCpp String packageName; /** Attribution tag. Mostly used for diagnostic purposes. */ - @nullable String attributionTag; + @nullable @utf8InCpp String attributionTag; } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 1cef0922a48e..e8e263147c6e 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -6729,7 +6729,7 @@ public class AudioManager { */ public Map<Integer, Boolean> getSurroundFormats() { Map<Integer, Boolean> surroundFormats = new HashMap<>(); - int status = AudioSystem.getSurroundFormats(surroundFormats, false); + int status = AudioSystem.getSurroundFormats(surroundFormats); if (status != AudioManager.SUCCESS) { // fail and bail! Log.e(TAG, "getSurroundFormats failed:" + status); @@ -6762,20 +6762,17 @@ public class AudioManager { /** * @hide * Returns all surround formats that are reported by the connected HDMI device. - * The keys are not affected by calling setSurroundFormatEnabled(), and the values - * are not affected by calling setSurroundFormatEnabled() when in AUTO mode. - * This information can used to show the AUTO setting for SurroundSound. + * The return values are not affected by calling setSurroundFormatEnabled. * - * @return a map where the key is a surround format and - * the value indicates the surround format is enabled or not + * @return a list of surround formats */ - public Map<Integer, Boolean> getReportedSurroundFormats() { - Map<Integer, Boolean> reportedSurroundFormats = new HashMap<>(); - int status = AudioSystem.getSurroundFormats(reportedSurroundFormats, true); + public ArrayList<Integer> getReportedSurroundFormats() { + ArrayList<Integer> reportedSurroundFormats = new ArrayList<>(); + int status = AudioSystem.getReportedSurroundFormats(reportedSurroundFormats); if (status != AudioManager.SUCCESS) { // fail and bail! Log.e(TAG, "getReportedSurroundFormats failed:" + status); - return new HashMap<Integer, Boolean>(); // Always return a map. + return new ArrayList<Integer>(); // Always return a list. } return reportedSurroundFormats; } @@ -7087,26 +7084,22 @@ public class AudioManager { * <pre class="prettyprint"> * // Get an AudioManager instance * AudioManager audioManager = Context.getSystemService(AudioManager.class); - * try { - * AudioDeviceInfo speakerDevice = null; - * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices(); - * for (AudioDeviceInfo device : devices) { - * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { - * speakerDevice = device; - * break; - * } + * AudioDeviceInfo speakerDevice = null; + * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices(); + * for (AudioDeviceInfo device : devices) { + * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { + * speakerDevice = device; + * break; * } - * if (speakerDevice != null) { - * // Turn speakerphone ON. - * boolean result = audioManager.setCommunicationDevice(speakerDevice); - * if (!result) { - * // Handle error. - * } - * // Turn speakerphone OFF. - * audioManager.clearCommunicationDevice(); + * } + * if (speakerDevice != null) { + * // Turn speakerphone ON. + * boolean result = audioManager.setCommunicationDevice(speakerDevice); + * if (!result) { + * // Handle error. * } - * } catch (IllegalArgumentException e) { - * // Handle exception. + * // Turn speakerphone OFF. + * audioManager.clearCommunicationDevice(); * } * </pre> * @param device the requested audio device. diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index bf04b660425b..d7112d6dfa63 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -16,6 +16,8 @@ package android.media; +import static android.media.permission.PermissionUtil.myIdentity; + import android.annotation.CallbackExecutor; import android.annotation.FloatRange; import android.annotation.IntDef; @@ -26,9 +28,11 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Context; import android.media.MediaRecorder.Source; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; +import android.media.permission.Identity; import android.media.projection.MediaProjection; import android.os.Binder; import android.os.Build; @@ -54,6 +58,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.concurrent.Executor; /** @@ -352,6 +357,32 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int sessionId) throws IllegalArgumentException { + this(attributes, format, bufferSizeInBytes, sessionId, ActivityThread.currentApplication()); + } + + /** + * @hide + * Class constructor with {@link AudioAttributes} and {@link AudioFormat}. + * @param attributes a non-null {@link AudioAttributes} instance. Use + * {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the audio + * source for this instance. + * @param format a non-null {@link AudioFormat} instance describing the format of the data + * that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for + * configuring the audio format parameters such as encoding, channel mask and sample rate. + * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written + * to during the recording. New audio data can be read from this buffer in smaller chunks + * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum + * required buffer size for the successful creation of an AudioRecord instance. Using values + * smaller than getMinBufferSize() will result in an initialization failure. + * @param sessionId ID of audio session the AudioRecord must be attached to, or + * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction + * time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before + * construction. + * @param context An optional context to pull an attribution tag from. + * @throws IllegalArgumentException + */ + private AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, + int sessionId, @Nullable Context context) throws IllegalArgumentException { mRecordingState = RECORDSTATE_STOPPED; if (attributes == null) { @@ -414,15 +445,21 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, audioBuffSizeCheck(bufferSizeInBytes); + Identity identity = myIdentity(context); + if (identity.packageName == null) { + // Command line utility + identity.packageName = "uid:" + Binder.getCallingUid(); + } + int[] sampleRate = new int[] {mSampleRate}; int[] session = new int[1]; session[0] = sessionId; //TODO: update native initialization when information about hardware init failure // due to capture device already open is available. - int initResult = native_setup( new WeakReference<AudioRecord>(this), + int initResult = native_setup(new WeakReference<AudioRecord>(this), mAudioAttributes, sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat, mNativeBufferSizeInBytes, - session, getCurrentOpPackageName(), 0 /*nativeRecordInJavaObj*/); + session, identity, 0 /*nativeRecordInJavaObj*/); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing native AudioRecord object."); return; // with mState == STATE_UNINITIALIZED @@ -434,15 +471,6 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, mState = STATE_INITIALIZED; } - private String getCurrentOpPackageName() { - String opPackageName = ActivityThread.currentOpPackageName(); - if (opPackageName != null) { - return opPackageName; - } - // Command line utility - return "uid:" + Binder.getCallingUid(); - } - /** * A constructor which explicitly connects a Native (C++) AudioRecord. For use by * the AudioRecordRoutingProxy subclass. @@ -492,7 +520,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, 0 /*mAudioFormat*/, 0 /*mNativeBufferSizeInBytes*/, session, - ActivityThread.currentOpPackageName(), + myIdentity(null), nativeRecordInJavaObj); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing native AudioRecord object."); @@ -548,6 +576,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, private AudioPlaybackCaptureConfiguration mAudioPlaybackCaptureConfiguration; private AudioAttributes mAttributes; private AudioFormat mFormat; + private Context mContext; private int mBufferSizeInBytes; private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE; private int mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT; @@ -583,6 +612,18 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, } /** + * Sets the context the record belongs to. + * @param context a non-null {@link Context} instance + * @return the same Builder instance. + */ + public @NonNull Builder setContext(@NonNull Context context) { + Objects.requireNonNull(context); + // keep reference, we only copy the data when building + mContext = context; + return this; + } + + /** * @hide * To be only used by system components. Allows specifying non-public capture presets * @param attributes a non-null {@link AudioAttributes} instance that contains the capture @@ -793,7 +834,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, * mFormat.getBytesPerSample(mFormat.getEncoding()); } final AudioRecord record = new AudioRecord( - mAttributes, mFormat, mBufferSizeInBytes, mSessionId); + mAttributes, mFormat, mBufferSizeInBytes, mSessionId, mContext); if (record.getState() == STATE_UNINITIALIZED) { // release is not necessary throw new UnsupportedOperationException("Cannot create AudioRecord"); @@ -2035,15 +2076,32 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, // Native methods called from the Java side //-------------------- - @UnsupportedAppUsage - private native final int native_setup(Object audiorecord_this, + /** + * @deprecated Use native_setup that takes an Identity object + * @return + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, + publicAlternatives = "{@code AudioRecord.Builder}") + @Deprecated + private int native_setup(Object audiorecordThis, Object /*AudioAttributes*/ attributes, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int[] sessionId, String opPackageName, - long nativeRecordInJavaObj); + long nativeRecordInJavaObj) { + Identity identity = myIdentity(null); + identity.packageName = opPackageName; + + return native_setup(audiorecordThis, attributes, sampleRate, channelMask, channelIndexMask, + audioFormat, buffSizeInBytes, sessionId, identity, nativeRecordInJavaObj); + } + + private native int native_setup(Object audiorecordThis, + Object /*AudioAttributes*/ attributes, + int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, + int buffSizeInBytes, int[] sessionId, Identity identity, long nativeRecordInJavaObj); // TODO remove: implementation calls directly into implementation of native_release() - private native final void native_finalize(); + private native void native_finalize(); /** * @hide diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index f1f6cb1f42be..8134d6f8352d 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -1699,8 +1699,10 @@ public class AudioSystem public static native int getMicrophones(ArrayList<MicrophoneInfo> microphonesInfo); /** @hide */ - public static native int getSurroundFormats(Map<Integer, Boolean> surroundFormats, - boolean reported); + public static native int getSurroundFormats(Map<Integer, Boolean> surroundFormats); + + /** @hide */ + public static native int getReportedSurroundFormats(ArrayList<Integer> surroundFormats); /** * @hide diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 9176dae8609f..3de78bb9ef9f 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -18,6 +18,7 @@ package android.media; import static android.Manifest.permission.BIND_IMS_SERVICE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.media.permission.PermissionUtil.myIdentity; import android.annotation.CallbackExecutor; import android.annotation.IntDef; @@ -34,6 +35,7 @@ import android.content.res.AssetFileDescriptor; import android.graphics.SurfaceTexture; import android.media.SubtitleController.Anchor; import android.media.SubtitleTrack.RenderingWidget; +import android.media.permission.Identity; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -53,6 +55,7 @@ import android.provider.Settings; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; @@ -684,11 +687,14 @@ public class MediaPlayer extends PlayerBase mTimeProvider = new TimeProvider(this); mOpenSubtitleSources = new Vector<InputStream>(); + Identity identity = myIdentity(null); + // set the package name to empty if it was null + identity.packageName = TextUtils.emptyIfNull(identity.packageName); + /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ - native_setup(new WeakReference<MediaPlayer>(this), - getCurrentOpPackageName()); + native_setup(new WeakReference<MediaPlayer>(this), identity); baseRegisterPlayer(sessionId); } @@ -2471,7 +2477,7 @@ public class MediaPlayer extends PlayerBase private native final int native_setMetadataFilter(Parcel request); private static native final void native_init(); - private native void native_setup(Object mediaplayerThis, @NonNull String opPackageName); + private native void native_setup(Object mediaplayerThis, @NonNull Identity identity); private native final void native_finalize(); /** diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 49a4cc6239bb..87e1e5bdb9ce 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -16,6 +16,8 @@ package android.media; +import static android.media.permission.PermissionUtil.myIdentity; + import android.annotation.CallbackExecutor; import android.annotation.FloatRange; import android.annotation.IntDef; @@ -25,7 +27,9 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Context; import android.hardware.Camera; +import android.media.permission.Identity; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -48,6 +52,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.Executor; /** @@ -127,9 +132,21 @@ public class MediaRecorder implements AudioRouting, /** * Default constructor. + * + * @deprecated Use {@link #MediaRecorder(Context)} instead */ + @Deprecated public MediaRecorder() { + this(ActivityThread.currentApplication()); + } + /** + * Default constructor. + * + * @param context Context the recorder belongs to + */ + public MediaRecorder(@NonNull Context context) { + Objects.requireNonNull(context); Looper looper; if ((looper = Looper.myLooper()) != null) { mEventHandler = new EventHandler(this, looper); @@ -140,12 +157,11 @@ public class MediaRecorder implements AudioRouting, } mChannelCount = 1; - String packageName = ActivityThread.currentPackageName(); /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ - native_setup(new WeakReference<MediaRecorder>(this), packageName, - ActivityThread.currentOpPackageName()); + native_setup(new WeakReference<MediaRecorder>(this), + ActivityThread.currentPackageName(), myIdentity(context)); } /** @@ -1740,12 +1756,22 @@ public class MediaRecorder implements AudioRouting, @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private static native final void native_init(); - @UnsupportedAppUsage - private native final void native_setup(Object mediarecorder_this, - String clientName, String opPackageName) throws IllegalStateException; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, + publicAlternatives = "{@link MediaRecorder}") + private void native_setup(Object mediarecorderThis, + String clientName, String opPackageName) throws IllegalStateException { + Identity identity = myIdentity(null); + identity.packageName = opPackageName; + + native_setup(mediarecorderThis, clientName, identity); + } + + private native void native_setup(Object mediarecorderThis, + String clientName, Identity identity) + throws IllegalStateException; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - private native final void native_finalize(); + private native void native_finalize(); @UnsupportedAppUsage private native void setParameter(String nameValuePair); diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index dc9c58ebf18c..b4db3055e58c 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -60,6 +60,7 @@ import java.util.stream.Collectors; public final class MediaRouter2 { private static final String TAG = "MR2"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final Object sSystemRouterLock = new Object(); private static final Object sRouterLock = new Object(); // The maximum time for the old routing controller available after transfer. @@ -67,8 +68,8 @@ public final class MediaRouter2 { // The manager request ID representing that no manager is involved. private static final long MANAGER_REQUEST_ID_NONE = MediaRoute2ProviderService.REQUEST_ID_NONE; - @GuardedBy("sRouterLock") - private static Map<String, MediaRouter2> sMediaRouter2Map = new ArrayMap<>(); + @GuardedBy("sSystemRouterLock") + private static Map<String, MediaRouter2> sSystemMediaRouter2Map = new ArrayMap<>(); private static MediaRouter2Manager sManager; @GuardedBy("sRouterLock") @@ -76,6 +77,7 @@ public final class MediaRouter2 { private final Context mContext; private final IMediaRouterService mMediaRouterService; + private final Object mLock = new Object(); private final CopyOnWriteArrayList<RouteCallbackRecord> mRouteCallbackRecords = new CopyOnWriteArrayList<>(); @@ -88,27 +90,29 @@ public final class MediaRouter2 { new CopyOnWriteArrayList<>(); private final String mClientPackageName; + private final ManagerCallback mManagerCallback; + private final String mPackageName; - @GuardedBy("sRouterLock") + @GuardedBy("mLock") final Map<String, MediaRoute2Info> mRoutes = new ArrayMap<>(); final RoutingController mSystemController; - @GuardedBy("sRouterLock") + @GuardedBy("mLock") private RouteDiscoveryPreference mDiscoveryPreference = RouteDiscoveryPreference.EMPTY; // TODO: Make MediaRouter2 is always connected to the MediaRouterService. - @GuardedBy("sRouterLock") + @GuardedBy("mLock") MediaRouter2Stub mStub; - @GuardedBy("sRouterLock") + @GuardedBy("mLock") private final Map<String, RoutingController> mNonSystemRoutingControllers = new ArrayMap<>(); private final AtomicInteger mNextRequestId = new AtomicInteger(1); final Handler mHandler; - @GuardedBy("sRouterLock") + @GuardedBy("mLock") private boolean mShouldUpdateRoutes = true; private volatile List<MediaRoute2Info> mFilteredRoutes = Collections.emptyList(); private volatile OnGetControllerHintsListener mOnGetControllerHintsListener; @@ -130,6 +134,11 @@ public final class MediaRouter2 { /** * Gets an instance of the media router which controls the app's media routing. * Returns {@code null} if the given package name is invalid. + * <p> + * Note: For media routers created with this method, the discovery preference passed to + * {@link #registerRouteCallback} will have no effect. The callback will be called accordingly + * with the client app's discovery preference. Therefore, it is recommended to pass + * {@link RouteDiscoveryPreference#EMPTY} there. * * @param clientPackageName the package name of the app to control * @hide @@ -149,15 +158,17 @@ public final class MediaRouter2 { return null; } - synchronized (sRouterLock) { - MediaRouter2 instance = sMediaRouter2Map.get(clientPackageName); + synchronized (sSystemRouterLock) { + MediaRouter2 instance = sSystemMediaRouter2Map.get(clientPackageName); if (instance == null) { // TODO: Add permission check here using MODIFY_AUDIO_ROUTING. if (sManager == null) { sManager = MediaRouter2Manager.getInstance(context.getApplicationContext()); } instance = new MediaRouter2(context, clientPackageName); - sMediaRouter2Map.put(clientPackageName, instance); + sSystemMediaRouter2Map.put(clientPackageName, instance); + // TODO: Remove router instance once it is not needed. + instance.registerManagerCallback(); } return instance; } @@ -192,11 +203,14 @@ public final class MediaRouter2 { } mSystemController = new SystemRoutingController(currentSystemSessionInfo); + // Only used by system MediaRouter2. mClientPackageName = null; + mManagerCallback = null; } private MediaRouter2(Context context, String clientPackageName) { mClientPackageName = clientPackageName; + mManagerCallback = new ManagerCallback(); mContext = context; mMediaRouterService = null; mPackageName = null; @@ -220,8 +234,8 @@ public final class MediaRouter2 { } /** - * Gets the target package name of the app which this media router controls. - * This is only non-null when the router instance is created with the target package name. + * Gets the client package name of the app which this media router controls. + * This is only non-null when the router instance is created with the client package name. * * @see #getInstance(Context, String) * @hide @@ -245,6 +259,9 @@ public final class MediaRouter2 { Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(routeCallback, "callback must not be null"); Objects.requireNonNull(preference, "preference must not be null"); + if (isSystemRouter()) { + preference = RouteDiscoveryPreference.EMPTY; + } RouteCallbackRecord record = new RouteCallbackRecord(executor, routeCallback, preference); @@ -253,7 +270,11 @@ public final class MediaRouter2 { // is happening but it's okay because either this or the other registration should be done. mRouteCallbackRecords.addIfAbsent(record); - synchronized (sRouterLock) { + if (isSystemRouter()) { + return; + } + + synchronized (mLock) { if (mStub == null) { MediaRouter2Stub stub = new MediaRouter2Stub(); try { @@ -289,7 +310,11 @@ public final class MediaRouter2 { return; } - synchronized (sRouterLock) { + if (isSystemRouter()) { + return; + } + + synchronized (mLock) { if (mStub == null) { return; } @@ -326,22 +351,37 @@ public final class MediaRouter2 { } /** + * Gets the list of all discovered routes. + * This list includes the routes that are not related to the client app. + * <p> + * This will return an empty list for non-system media routers. + * + * @hide + */ + //@SystemApi + public List<MediaRoute2Info> getAllRoutes() { + if (isSystemRouter()) { + return sManager.getAllRoutes(); + } + return Collections.emptyList(); + } + + /** * Gets the unmodifiable list of {@link MediaRoute2Info routes} currently * known to the media router. * <p> * Please note that the list can be changed before callbacks are invoked. * </p> - * * @return the list of routes that contains at least one of the route features in discovery * preferences registered by the application */ @NonNull public List<MediaRoute2Info> getRoutes() { - if (mClientPackageName != null) { + if (isSystemRouter()) { return sManager.getAvailableRoutes(mClientPackageName); } - synchronized (sRouterLock) { + synchronized (mLock) { if (mShouldUpdateRoutes) { mShouldUpdateRoutes = false; @@ -449,7 +489,7 @@ public final class MediaRouter2 { * @see TransferCallback#onTransferFailure */ public void transferTo(@NonNull MediaRoute2Info route) { - if (mClientPackageName != null) { + if (isSystemRouter()) { sManager.selectRoute(mClientPackageName, route); return; } @@ -464,7 +504,7 @@ public final class MediaRouter2 { * controls the media routing, this method is a no-op. */ public void stop() { - if (mClientPackageName != null) { + if (isSystemRouter()) { List<RoutingSessionInfo> sessionInfos = sManager.getRoutingSessions(mClientPackageName); RoutingSessionInfo sessionToRelease = sessionInfos.get(sessionInfos.size() - 1); sManager.releaseSession(sessionToRelease); @@ -481,7 +521,7 @@ public final class MediaRouter2 { */ //@SystemApi public void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) { - if (mClientPackageName != null) { + if (isSystemRouter()) { sManager.transfer(controller.getRoutingSessionInfo(), route); return; } @@ -490,7 +530,7 @@ public final class MediaRouter2 { Objects.requireNonNull(route, "route must not be null"); boolean routeFound; - synchronized (sRouterLock) { + synchronized (mLock) { // TODO: Check thread-safety routeFound = mRoutes.containsKey(route.getId()); } @@ -526,7 +566,7 @@ public final class MediaRouter2 { } MediaRouter2Stub stub; - synchronized (sRouterLock) { + synchronized (mLock) { stub = mStub; } if (stub != null) { @@ -576,7 +616,7 @@ public final class MediaRouter2 { public List<RoutingController> getControllers() { // TODO: Do not create the controller instances every time, // Instead, update the list using the sessions' ID and session related callbacks. - if (mClientPackageName != null) { + if (isSystemRouter()) { return sManager.getRoutingSessions(mClientPackageName).stream() .map(info -> new RoutingController(info)) .collect(Collectors.toList()); @@ -584,7 +624,7 @@ public final class MediaRouter2 { List<RoutingController> result = new ArrayList<>(); result.add(0, mSystemController); - synchronized (sRouterLock) { + synchronized (mLock) { result.addAll(mNonSystemRoutingControllers.values()); } return result; @@ -603,7 +643,7 @@ public final class MediaRouter2 { Objects.requireNonNull(route, "route must not be null"); MediaRouter2Stub stub; - synchronized (sRouterLock) { + synchronized (mLock) { stub = mStub; } if (stub != null) { @@ -627,7 +667,7 @@ public final class MediaRouter2 { List<MediaRoute2Info> removedRoutes = new ArrayList<>(); List<MediaRoute2Info> changedRoutes = new ArrayList<>(); - synchronized (sRouterLock) { + synchronized (mLock) { List<String> currentRoutesIds = currentRoutes.stream().map(MediaRoute2Info::getId) .collect(Collectors.toList()); @@ -685,7 +725,7 @@ public final class MediaRouter2 { void addRoutesOnHandler(List<MediaRoute2Info> routes) { List<MediaRoute2Info> addedRoutes = new ArrayList<>(); - synchronized (sRouterLock) { + synchronized (mLock) { for (MediaRoute2Info route : routes) { mRoutes.put(route.getId(), route); if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { @@ -701,7 +741,7 @@ public final class MediaRouter2 { void removeRoutesOnHandler(List<MediaRoute2Info> routes) { List<MediaRoute2Info> removedRoutes = new ArrayList<>(); - synchronized (sRouterLock) { + synchronized (mLock) { for (MediaRoute2Info route : routes) { mRoutes.remove(route.getId()); if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { @@ -717,7 +757,7 @@ public final class MediaRouter2 { void changeRoutesOnHandler(List<MediaRoute2Info> routes) { List<MediaRoute2Info> changedRoutes = new ArrayList<>(); - synchronized (sRouterLock) { + synchronized (mLock) { for (MediaRoute2Info route : routes) { mRoutes.put(route.getId(), route); if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) { @@ -789,7 +829,7 @@ public final class MediaRouter2 { newController.setRoutingSessionInfo(sessionInfo); } else { newController = new RoutingController(sessionInfo); - synchronized (sRouterLock) { + synchronized (mLock) { mNonSystemRoutingControllers.put(newController.getId(), newController); } } @@ -812,7 +852,7 @@ public final class MediaRouter2 { } RoutingController matchingController; - synchronized (sRouterLock) { + synchronized (mLock) { matchingController = mNonSystemRoutingControllers.get(sessionInfo.getId()); } @@ -840,7 +880,7 @@ public final class MediaRouter2 { } RoutingController matchingController; - synchronized (sRouterLock) { + synchronized (mLock) { matchingController = mNonSystemRoutingControllers.get(sessionInfo.getId()); } @@ -868,7 +908,7 @@ public final class MediaRouter2 { if (oldSession.isSystemSession()) { controller = getSystemController(); } else { - synchronized (sRouterLock) { + synchronized (mLock) { controller = mNonSystemRoutingControllers.get(oldSession.getId()); } } @@ -878,6 +918,22 @@ public final class MediaRouter2 { requestCreateController(controller, route, managerRequestId); } + /** + * Returns whether this router is created with {@link #getInstance(Context, String)}. + * This kind of router can control the target app's media routing. + */ + private boolean isSystemRouter() { + return mClientPackageName != null; + } + + /** + * Registers {@link MediaRouter2Manager.Callback} for getting events. + */ + private void registerManagerCallback() { + // Using direct executor here, since MediaRouter2Manager also posts to the main handler. + sManager.registerCallback(Runnable::run, mManagerCallback); + } + private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes, RouteDiscoveryPreference discoveryRequest) { return routes.stream() @@ -1236,7 +1292,7 @@ public final class MediaRouter2 { } MediaRouter2Stub stub; - synchronized (sRouterLock) { + synchronized (mLock) { stub = mStub; } if (stub != null) { @@ -1283,7 +1339,7 @@ public final class MediaRouter2 { } MediaRouter2Stub stub; - synchronized (sRouterLock) { + synchronized (mLock) { stub = mStub; } if (stub != null) { @@ -1318,7 +1374,7 @@ public final class MediaRouter2 { } MediaRouter2Stub stub; - synchronized (sRouterLock) { + synchronized (mLock) { stub = mStub; } if (stub != null) { @@ -1352,7 +1408,7 @@ public final class MediaRouter2 { return; } MediaRouter2Stub stub; - synchronized (sRouterLock) { + synchronized (mLock) { stub = mStub; } if (stub != null) { @@ -1386,7 +1442,7 @@ public final class MediaRouter2 { mState = CONTROLLER_STATE_RELEASING; } - synchronized (sRouterLock) { + synchronized (mLock) { // It could happen if the controller is released by the another thread // in between two locks if (!mNonSystemRoutingControllers.remove(getId(), this)) { @@ -1415,7 +1471,7 @@ public final class MediaRouter2 { mState = CONTROLLER_STATE_RELEASED; } - synchronized (sRouterLock) { + synchronized (mLock) { mNonSystemRoutingControllers.remove(getId(), this); if (shouldReleaseSession && mStub != null) { @@ -1483,7 +1539,7 @@ public final class MediaRouter2 { } private List<MediaRoute2Info> getRoutesWithIds(List<String> routeIds) { - synchronized (sRouterLock) { + synchronized (mLock) { return routeIds.stream().map(mRoutes::get) .filter(Objects::nonNull) .collect(Collectors.toList()); @@ -1665,4 +1721,79 @@ public final class MediaRouter2 { MediaRouter2.this, oldSession, route, managerRequestId)); } } + + class ManagerCallback implements MediaRouter2Manager.Callback { + + @Override + public void onRoutesAdded(@NonNull List<MediaRoute2Info> routes) { + List<MediaRoute2Info> filteredRoutes = + sManager.filterRoutesForPackage(routes, mClientPackageName); + if (filteredRoutes.isEmpty()) { + return; + } + for (RouteCallbackRecord record: mRouteCallbackRecords) { + record.mExecutor.execute( + () -> record.mRouteCallback.onRoutesAdded(filteredRoutes)); + } + } + + @Override + public void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) { + List<MediaRoute2Info> filteredRoutes = + sManager.filterRoutesForPackage(routes, mClientPackageName); + if (filteredRoutes.isEmpty()) { + return; + } + for (RouteCallbackRecord record: mRouteCallbackRecords) { + record.mExecutor.execute( + () -> record.mRouteCallback.onRoutesRemoved(filteredRoutes)); + } + } + + @Override + public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) { + List<MediaRoute2Info> filteredRoutes = + sManager.filterRoutesForPackage(routes, mClientPackageName); + if (filteredRoutes.isEmpty()) { + return; + } + for (RouteCallbackRecord record: mRouteCallbackRecords) { + record.mExecutor.execute( + () -> record.mRouteCallback.onRoutesChanged(filteredRoutes)); + } + } + + @Override + public void onSessionUpdated(@NonNull RoutingSessionInfo session) { + // TODO: Call ControllerCallback.onControllerUpdated + } + + @Override + public void onTransferred(@NonNull RoutingSessionInfo oldSession, + @Nullable RoutingSessionInfo newSession) { + // TODO: Call TransferCallback.onTransfer + } + + @Override + public void onTransferFailed(@NonNull RoutingSessionInfo session, + @NonNull MediaRoute2Info route) { + // TODO: Call TransferCallback.onTransferFailure + } + + @Override + public void onSessionReleased(@NonNull RoutingSessionInfo session) { + // TODO: Call TransferCallback.onStop() + } + + @Override + public void onPreferredFeaturesChanged(@NonNull String packageName, + @NonNull List<String> preferredFeatures) { + // Does nothing. + } + + @Override + public void onRequestFailed(int reason) { + // Does nothing. + } + } } diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java index 5e732f9be68f..ca619d4072c3 100644 --- a/media/java/android/media/MediaRouter2Manager.java +++ b/media/java/android/media/MediaRouter2Manager.java @@ -237,6 +237,36 @@ public final class MediaRouter2Manager { } /** + * Returns a list of routes which are related to the given package name in the given route list. + */ + @NonNull + public List<MediaRoute2Info> filterRoutesForPackage(@NonNull List<MediaRoute2Info> routes, + @NonNull String packageName) { + Objects.requireNonNull(routes, "routes must not be null"); + Objects.requireNonNull(packageName, "packageName must not be null"); + + List<RoutingSessionInfo> sessions = getRoutingSessions(packageName); + RoutingSessionInfo sessionInfo = sessions.get(sessions.size() - 1); + + List<MediaRoute2Info> result = new ArrayList<>(); + List<String> preferredFeatures = mPreferredFeaturesMap.get(packageName); + if (preferredFeatures == null) { + preferredFeatures = Collections.emptyList(); + } + + synchronized (mRoutesLock) { + for (MediaRoute2Info route : routes) { + if (route.hasAnyFeatures(preferredFeatures) + || sessionInfo.getSelectedRoutes().contains(route.getId()) + || sessionInfo.getTransferableRoutes().contains(route.getId())) { + result.add(route); + } + } + } + return result; + } + + /** * Gets the system routing session associated with no specific application. */ @NonNull diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 67a4a4b1f851..fd3c4057ad21 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -16,6 +16,8 @@ package android.media.audiofx; +import static android.media.permission.PermissionUtil.myIdentity; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -23,11 +25,11 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioSystem; +import android.media.permission.Identity; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -515,10 +517,11 @@ public class AudioEffect { } // native initialization + // TODO b/182469354: Make consistent with AudioRecord int initResult = native_setup(new WeakReference<AudioEffect>(this), type.toString(), uuid.toString(), priority, audioSession, deviceType, deviceAddress, - id, desc, ActivityThread.currentOpPackageName(), probe); + id, desc, myIdentity(null), probe); if (initResult != SUCCESS && initResult != ALREADY_EXISTS) { Log.e(TAG, "Error code " + initResult + " when initializing AudioEffect."); @@ -1385,7 +1388,7 @@ public class AudioEffect { private native final int native_setup(Object audioeffect_this, String type, String uuid, int priority, int audioSession, int deviceType, String deviceAddress, int[] id, Object[] desc, - String opPackageName, boolean probe); + Identity identity, boolean probe); private native final void native_finalize(); diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java index a5da648cf14a..58c9e650bb90 100644 --- a/media/java/android/media/audiofx/Visualizer.java +++ b/media/java/android/media/audiofx/Visualizer.java @@ -16,8 +16,10 @@ package android.media.audiofx; -import android.app.ActivityThread; +import static android.media.permission.PermissionUtil.myIdentity; + import android.compat.annotation.UnsupportedAppUsage; +import android.media.permission.Identity; import android.os.Handler; import android.os.Looper; import android.util.Log; @@ -217,9 +219,11 @@ public class Visualizer { synchronized (mStateLock) { mState = STATE_UNINITIALIZED; + // native initialization + // TODO b/182469354: make consistent with AudioRecord int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id, - ActivityThread.currentOpPackageName()); + myIdentity(null)); if (result != SUCCESS && result != ALREADY_EXISTS) { Log.e(TAG, "Error code "+result+" when initializing Visualizer."); switch (result) { @@ -686,7 +690,7 @@ public class Visualizer { private native final int native_setup(Object audioeffect_this, int audioSession, int[] id, - String opPackageName); + Identity identity); @GuardedBy("mStateLock") private native final void native_finalize(); diff --git a/media/java/android/media/metrics/NetworkEvent.java b/media/java/android/media/metrics/NetworkEvent.java index 098885cc9bdd..186606825104 100644 --- a/media/java/android/media/metrics/NetworkEvent.java +++ b/media/java/android/media/metrics/NetworkEvent.java @@ -113,10 +113,11 @@ public final class NetworkEvent extends Event implements Parcelable { * * @hide */ - public NetworkEvent(@NetworkType int type, long timeSinceCreatedMillis, Bundle extras) { + public NetworkEvent(@NetworkType int type, long timeSinceCreatedMillis, + @Nullable Bundle extras) { this.mNetworkType = type; this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; - this.mExtras = extras.deepCopy(); + this.mExtras = extras == null ? null : extras.deepCopy(); } /** diff --git a/media/java/android/media/metrics/PlaybackErrorEvent.java b/media/java/android/media/metrics/PlaybackErrorEvent.java index b23b4d2728b4..ccf848b50a36 100644 --- a/media/java/android/media/metrics/PlaybackErrorEvent.java +++ b/media/java/android/media/metrics/PlaybackErrorEvent.java @@ -65,12 +65,12 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { int errorCode, int subErrorCode, long timeSinceCreatedMillis, - Bundle extras) { + @Nullable Bundle extras) { this.mExceptionStack = exceptionStack; this.mErrorCode = errorCode; this.mSubErrorCode = subErrorCode; this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; - this.mExtras = extras.deepCopy(); + this.mExtras = extras == null ? null : extras.deepCopy(); } /** @hide */ diff --git a/media/java/android/media/metrics/PlaybackMetrics.java b/media/java/android/media/metrics/PlaybackMetrics.java index 7e7f44a97b9c..3ffd10f4ea8c 100644 --- a/media/java/android/media/metrics/PlaybackMetrics.java +++ b/media/java/android/media/metrics/PlaybackMetrics.java @@ -194,7 +194,7 @@ public final class PlaybackMetrics implements Parcelable { long localBytesRead, long networkTransferDurationMillis, byte[] drmSessionId, - Bundle extras) { + @Nullable Bundle extras) { this.mMediaDurationMillis = mediaDurationMillis; this.mStreamSource = streamSource; this.mStreamType = streamType; @@ -212,7 +212,7 @@ public final class PlaybackMetrics implements Parcelable { this.mLocalBytesRead = localBytesRead; this.mNetworkTransferDurationMillis = networkTransferDurationMillis; this.mDrmSessionId = drmSessionId; - this.mExtras = extras.deepCopy(); + this.mExtras = extras == null ? null : extras.deepCopy(); } /** diff --git a/media/java/android/media/metrics/PlaybackStateEvent.java b/media/java/android/media/metrics/PlaybackStateEvent.java index dea8c1db71de..2bab5c9bc3dc 100644 --- a/media/java/android/media/metrics/PlaybackStateEvent.java +++ b/media/java/android/media/metrics/PlaybackStateEvent.java @@ -138,10 +138,10 @@ public final class PlaybackStateEvent extends Event implements Parcelable { public PlaybackStateEvent( int state, long timeSinceCreatedMillis, - Bundle extras) { + @Nullable Bundle extras) { this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; this.mState = state; - this.mExtras = extras.deepCopy(); + this.mExtras = extras == null ? null : extras.deepCopy(); } /** diff --git a/media/java/android/media/metrics/TrackChangeEvent.java b/media/java/android/media/metrics/TrackChangeEvent.java index aa519782ec80..a3eb4adfeb8d 100644 --- a/media/java/android/media/metrics/TrackChangeEvent.java +++ b/media/java/android/media/metrics/TrackChangeEvent.java @@ -167,7 +167,7 @@ public final class TrackChangeEvent extends Event implements Parcelable { this.mWidth = width; this.mHeight = height; this.mVideoFrameRate = videoFrameRate; - this.mExtras = extras.deepCopy(); + this.mExtras = extras == null ? null : extras.deepCopy(); } /** diff --git a/media/java/android/media/permission/PermissionUtil.java b/media/java/android/media/permission/PermissionUtil.java index 315ee4f1e998..92fe8820570c 100644 --- a/media/java/android/media/permission/PermissionUtil.java +++ b/media/java/android/media/permission/PermissionUtil.java @@ -17,9 +17,12 @@ package android.media.permission; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityThread; import android.content.Context; import android.content.PermissionChecker; import android.os.Binder; +import android.os.Process; import java.util.Objects; @@ -49,6 +52,25 @@ import java.util.Objects; */ public class PermissionUtil { /** + * Create an identity for the current process and the passed context. + * + * @param context The process the identity is for. If {@code null}, the process's default + * identity is chosen. + * @return The identity for the current process and context + */ + public static @NonNull Identity myIdentity(@Nullable Context context) { + Identity identity = new Identity(); + + identity.pid = Process.myPid(); + identity.uid = Process.myUid(); + identity.packageName = context != null ? context.getOpPackageName() + : ActivityThread.currentOpPackageName(); + identity.attributionTag = context != null ? context.getAttributionTag() : null; + + return identity; + } + + /** * Authenticate an originator, where the binder call is coming from a middleman. * * The middleman is expected to hold a special permission to act as such, or else a diff --git a/media/jni/Android.bp b/media/jni/Android.bp index ce4550492740..f09dcde1ee28 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -84,6 +84,7 @@ cc_library_shared { "android.hardware.drm@1.4", "android.hidl.memory@1.0", "android.hidl.token@1.0-utils", + "media_permission-aidl-cpp", ], header_libs: [ @@ -182,7 +183,7 @@ cc_library_shared { "libnativehelper", "libutils", "tv_tuner_aidl_interface-ndk_platform", - "tv_tuner_resource_manager_aidl_interface-ndk_platform" + "tv_tuner_resource_manager_aidl_interface-ndk_platform", ], static_libs: [ @@ -212,4 +213,3 @@ cc_library_shared { "-Wunreachable-code", ], } - diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 98ac5b983098..a3607597f05e 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaPlayer-JNI" +#include "permission_utils.h" #include "utils/Log.h" #include <media/mediaplayer.h> @@ -79,6 +80,8 @@ static StateExceptionFields gStateExceptionFields; using namespace android; using media::VolumeShaper; +using media::permission::Identity; +using media::permission::convertIdentity; // ---------------------------------------------------------------------------- @@ -946,11 +949,11 @@ android_media_MediaPlayer_native_init(JNIEnv *env) static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jstring opPackageName) + jobject jIdentity) { ALOGV("native_setup"); - ScopedUtfChars opPackageNameStr(env, opPackageName); - sp<MediaPlayer> mp = new MediaPlayer(opPackageNameStr.c_str()); + + sp<MediaPlayer> mp = new MediaPlayer(convertIdentity(env, jIdentity)); if (mp == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; @@ -1406,7 +1409,7 @@ static const JNINativeMethod gMethods[] = { {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;)V",(void *)android_media_MediaPlayer_native_setup}, + {"native_setup", "(Ljava/lang/Object;Landroid/media/permission/Identity;)V",(void *)android_media_MediaPlayer_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, {"native_setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index f99dc012be95..66411233216f 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -24,6 +24,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaRecorderJNI" +#include "permission_utils.h" #include <utils/Log.h> #include <gui/Surface.h> @@ -50,6 +51,8 @@ using namespace android; +using android::media::permission::convertIdentity; + // ---------------------------------------------------------------------------- // helper function to extract a native Camera object from a Camera Java object @@ -617,13 +620,12 @@ android_media_MediaRecorder_native_init(JNIEnv *env) static void android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jstring packageName, jstring opPackageName) + jstring packageName, jobject jIdentity) { ALOGV("setup"); - ScopedUtfChars opPackageNameStr(env, opPackageName); + sp<MediaRecorder> mr = new MediaRecorder(convertIdentity(env, jIdentity)); - sp<MediaRecorder> mr = new MediaRecorder(String16(opPackageNameStr.c_str())); if (mr == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; @@ -869,7 +871,7 @@ static const JNINativeMethod gMethods[] = { {"native_reset", "()V", (void *)android_media_MediaRecorder_native_reset}, {"release", "()V", (void *)android_media_MediaRecorder_release}, {"native_init", "()V", (void *)android_media_MediaRecorder_native_init}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", + {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Landroid/media/permission/Identity;)V", (void *)android_media_MediaRecorder_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaRecorder_native_finalize}, {"native_setInputSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaRecorder_setInputSurface }, diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp index c2fc91d5cfea..bfed983c8bce 100644 --- a/media/jni/audioeffect/Android.bp +++ b/media/jni/audioeffect/Android.bp @@ -27,6 +27,11 @@ cc_library_shared { "libaudioclient", "libaudioutils", "libaudiofoundation", + "media_permission-aidl-cpp", + ], + + export_shared_lib_headers: [ + "media_permission-aidl-cpp", ], version_script: "exports.lds", diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp index a74ae5307a36..8a52456849f0 100644 --- a/media/jni/audioeffect/Visualizer.cpp +++ b/media/jni/audioeffect/Visualizer.cpp @@ -34,8 +34,8 @@ namespace android { // --------------------------------------------------------------------------- -Visualizer::Visualizer (const String16& opPackageName) - : AudioEffect(opPackageName) +Visualizer::Visualizer (const Identity& identity) + : AudioEffect(identity) { } diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h index 8b6a62f25638..3ee91f0f8b1e 100644 --- a/media/jni/audioeffect/Visualizer.h +++ b/media/jni/audioeffect/Visualizer.h @@ -20,6 +20,9 @@ #include <media/AudioEffect.h> #include <system/audio_effects/effect_visualizer.h> #include <utils/Thread.h> +#include "android/media/permission/Identity.h" + +using namespace android::media::permission; /** * The Visualizer class enables application to retrieve part of the currently playing audio for @@ -65,7 +68,7 @@ public: /* Constructor. * See AudioEffect constructor for details on parameters. */ - explicit Visualizer(const String16& opPackageName); + explicit Visualizer(const Identity& identity); ~Visualizer(); diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index 0d53ab152129..953b7e01c983 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -25,6 +25,7 @@ #include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> #include "media/AudioEffect.h" +#include "permission_utils.h" #include <nativehelper/ScopedUtfChars.h> @@ -34,6 +35,8 @@ using namespace android; +using media::permission::convertIdentity; + #define AUDIOEFFECT_SUCCESS 0 #define AUDIOEFFECT_ERROR (-1) #define AUDIOEFFECT_ERROR_ALREADY_EXISTS (-2) @@ -270,7 +273,7 @@ static jint android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, jstring type, jstring uuid, jint priority, jint sessionId, jint deviceType, jstring deviceAddress, - jintArray jId, jobjectArray javadesc, jstring opPackageName, jboolean probe) + jintArray jId, jobjectArray javadesc, jobject jIdentity, jboolean probe) { ALOGV("android_media_AudioEffect_native_setup"); AudioEffectJniStorage* lpJniStorage = NULL; @@ -283,8 +286,6 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t jobject jdesc; AudioDeviceTypeAddr device; - ScopedUtfChars opPackageNameStr(env, opPackageName); - setAudioEffect(env, thiz, 0); if (type != NULL) { @@ -337,7 +338,7 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t } // create the native AudioEffect object - lpAudioEffect = new AudioEffect(String16(opPackageNameStr.c_str())); + lpAudioEffect = new AudioEffect(convertIdentity(env, jIdentity)); if (lpAudioEffect == 0) { ALOGE("Error creating AudioEffect"); goto setup_failure; @@ -773,7 +774,7 @@ android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz _ // Dalvik VM type signatures static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_AudioEffect_native_init}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;[I[Ljava/lang/Object;Ljava/lang/String;Z)I", + {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;IIILjava/lang/String;[I[Ljava/lang/Object;Landroid/media/permission/Identity;Z)I", (void *)android_media_AudioEffect_native_setup}, {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize}, {"native_release", "()V", (void *)android_media_AudioEffect_native_release}, diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index 4c5970a30a05..439715cbb811 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -25,6 +25,7 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/threads.h> #include "Visualizer.h" +#include "permission_utils.h" #include <nativehelper/ScopedUtfChars.h> @@ -347,7 +348,7 @@ static void android_media_visualizer_effect_callback(int32_t event, static jint android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, - jint sessionId, jintArray jId, jstring opPackageName) + jint sessionId, jintArray jId, jobject jIdentity) { ALOGV("android_media_visualizer_native_setup"); VisualizerJniStorage* lpJniStorage = NULL; @@ -355,8 +356,6 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th sp<Visualizer> lpVisualizer; jint* nId = NULL; - ScopedUtfChars opPackageNameStr(env, opPackageName); - setVisualizer(env, thiz, 0); lpJniStorage = new VisualizerJniStorage(); @@ -382,7 +381,7 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th } // create the native Visualizer object - lpVisualizer = new Visualizer(String16(opPackageNameStr.c_str())); + lpVisualizer = new Visualizer(convertIdentity(env, jIdentity)); if (lpVisualizer == 0) { ALOGE("Error creating Visualizer"); goto setup_failure; @@ -679,7 +678,7 @@ android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean // Dalvik VM type signatures static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_visualizer_native_init}, - {"native_setup", "(Ljava/lang/Object;I[ILjava/lang/String;)I", + {"native_setup", "(Ljava/lang/Object;I[ILandroid/media/permission/Identity;)I", (void *)android_media_visualizer_native_setup}, {"native_finalize", "()V", (void *)android_media_visualizer_native_finalize}, {"native_release", "()V", (void *)android_media_visualizer_native_release}, diff --git a/media/jni/soundpool/Android.bp b/media/jni/soundpool/Android.bp index b3406cd89046..4227cd8cbb29 100644 --- a/media/jni/soundpool/Android.bp +++ b/media/jni/soundpool/Android.bp @@ -63,7 +63,7 @@ tidy_errors = [ // Remove some pedantic stylistic requirements. "-google-readability-casting", // C++ casts not always necessary and may be verbose - "-google-readability-todo", // do not require TODO(info) + "-google-readability-todo", // do not require TODO(info) "-google-build-using-namespace", // Reenable and fix later. "-google-explicit-constructor", // found in StreamManager.h @@ -100,7 +100,7 @@ cc_defaults { tidy_checks: tidy_errors, tidy_checks_as_errors: tidy_errors, tidy_flags: [ - "-format-style=file", + "-format-style=file", ], } @@ -135,6 +135,7 @@ cc_library_shared { "libaudioclient", "libmediandk", "libbinder", + "media_permission-aidl-cpp", ], cflags: [ diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp index 73e319a5902e..abb0f1208bc2 100644 --- a/media/jni/soundpool/Stream.cpp +++ b/media/jni/soundpool/Stream.cpp @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "SoundPool::Stream" #include <utils/Log.h> +#include<android/media/permission/Identity.h> #include "Stream.h" @@ -24,6 +25,8 @@ namespace android::soundpool { +using media::permission::Identity; + Stream::~Stream() { ALOGV("%s(%p)", __func__, this); @@ -326,15 +329,17 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, // do not create a new audio track if current track is compatible with sound parameters + Identity identity = Identity(); + identity.packageName = mStreamManager->getOpPackageName(); + // TODO b/182469354 make consistent with AudioRecord, add util for native source newTrack = new AudioTrack(streamType, sampleRate, sound->getFormat(), channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, staticCallback, userData, 0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE, AudioTrack::TRANSFER_DEFAULT, - nullptr /*offloadInfo*/, -1 /*uid*/, -1 /*pid*/, + nullptr /*offloadInfo*/, identity, mStreamManager->getAttributes(), - false /*doNotReconnect*/, 1.0f /*maxRequiredSpeed*/, - mStreamManager->getOpPackageName()); + false /*doNotReconnect*/, 1.0f /*maxRequiredSpeed*/); // Set caller name so it can be logged in destructor. // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_SOUNDPOOL newTrack->setCallerName("soundpool"); diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml index cdf4851a3e3d..ed120b53d636 100644 --- a/packages/CompanionDeviceManager/res/values-af/strings.xml +++ b/packages/CompanionDeviceManager/res/values-af/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Kies \'n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om deur <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> bestuur te word"</string> <string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string> <string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Stel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> om jou <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te bestuur – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Jy het <xliff:g id="APP_NAME">%1$s</xliff:g> nodig om jou <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te bestuur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> - <string name="consent_no" msgid="1335543792857823917">"Nee, dankie"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml index a03ea0dfcd4c..76f68e7ee495 100644 --- a/packages/CompanionDeviceManager/res/values-am/strings.xml +++ b/packages/CompanionDeviceManager/res/values-am/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"በ<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> የሚተዳደር <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string> <string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string> <string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> የእርስዎን <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> እንዲያስተዳድር ያቀናብሩት"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> የእርስዎን <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ለማስተዳደር ያስፈልጋል። <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"አዎ"</string> - <string name="consent_no" msgid="1335543792857823917">"አይ፣ አመሰግናለሁ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml index 970c46bd6133..92783a529cfc 100644 --- a/packages/CompanionDeviceManager/res/values-ar/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"اختَر <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ليديره تطبيق <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string> <string name="profile_name_watch" msgid="576290739483672360">"ساعة"</string> - <string name="confirmation_title" msgid="4751119145078041732">"اضبط <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> لإدارة <xliff:g id="PROFILE_NAME">%2$s</xliff:g> على <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"يجب توفّر تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> لإدارة <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"نعم"</string> - <string name="consent_no" msgid="1335543792857823917">"لا، شكرًا"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml index 477844c2a477..34ce062e0f4a 100644 --- a/packages/CompanionDeviceManager/res/values-as/strings.xml +++ b/packages/CompanionDeviceManager/res/values-as/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>এ পৰিচালনা কৰিব লগা এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string> <string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string> - <string name="confirmation_title" msgid="4751119145078041732">"আপোনাৰ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> পৰিচালনা কৰিবলৈ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ছেট কৰক - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"আপোনাৰ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> পৰিচালনা কৰিবলৈ <xliff:g id="APP_NAME">%1$s</xliff:g>ৰ আৱশ্যক। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"হয়"</string> - <string name="consent_no" msgid="1335543792857823917">"নালাগে, ধন্যবাদ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml index f10c639a0368..b07cad615d57 100644 --- a/packages/CompanionDeviceManager/res/values-az/strings.xml +++ b/packages/CompanionDeviceManager/res/values-az/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> tərəfindən idarə ediləcək <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string> <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string> <string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> profilinizin <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tərəfindən idarə olunmasını ayarlayın - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> profilinizi idarə etmək üçün <xliff:g id="APP_NAME">%1$s</xliff:g> tələb olunur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Bəli"</string> - <string name="consent_no" msgid="1335543792857823917">"Xeyr, çox sağolun"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml index e8542f364027..edeaa7785e36 100644 --- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="profile_name_watch" msgid="576290739483672360">"sat"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Podesite aplikaciju <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je neophodna za upravljanje profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Da"</string> - <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml index 13be6f245ac0..9410d686133b 100644 --- a/packages/CompanionDeviceManager/res/values-be/strings.xml +++ b/packages/CompanionDeviceManager/res/values-be/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Выберыце прыладу (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string> <string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> кіраваць прыладай \"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>\" – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Для кіравання прыладай \"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>\" патрабуецца праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\". <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Так"</string> - <string name="consent_no" msgid="1335543792857823917">"Не, дзякуй"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml index 3bda5e6104c8..4457dbd2cb3a 100644 --- a/packages/CompanionDeviceManager/res/values-bg/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Изберете устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), което да се управлява от <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string> <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Задайте <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управлява устройството ви (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"За управление на <xliff:g id="PROFILE_NAME">%2$s</xliff:g> се изисква <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Да"</string> - <string name="consent_no" msgid="1335543792857823917">"Не, благодаря"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml index d3bc5152af9a..4aa7e74e5432 100644 --- a/packages/CompanionDeviceManager/res/values-bn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন যেটি <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ম্যানেজ করবে"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string> <string name="profile_name_watch" msgid="576290739483672360">"দেখুন"</string> - <string name="confirmation_title" msgid="4751119145078041732">"আপনার <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ম্যানেজ করার জন্য <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> সেট করুন"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g>-কে আপনার <xliff:g id="PROFILE_NAME">%2$s</xliff:g>.ম্যানেজ করতে দিতে হবে। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"হ্যাঁ"</string> - <string name="consent_no" msgid="1335543792857823917">"না থাক"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml index 905b3061ffc6..8ffa3272fb8c 100644 --- a/packages/CompanionDeviceManager/res/values-bs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Odaberite uređaj <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="profile_name_watch" msgid="576290739483672360">"sat"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Postavite aplikaciju <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja vašim uređajem <xliff:g id="PROFILE_NAME">%2$s</xliff:g> — <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Potrebna je aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> za upravljanje uređajem <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Da"</string> - <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml index 86dc6940abe2..c9c186eba741 100644 --- a/packages/CompanionDeviceManager/res/values-ca/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> perquè el gestioni <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string> <string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Defineix que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestioni el teu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>)"</string> - <string name="profile_summary" msgid="2009764182871566255">"L\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g> és necessària per gestionar el teu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Sí"</string> - <string name="consent_no" msgid="1335543792857823917">"No, gràcies"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml index 389ccd0ccc95..b2ac32db2a99 100644 --- a/packages/CompanionDeviceManager/res/values-cs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete spravovat pomocí aplikace <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string> <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Nastavit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ke správě tohoto zařízení: <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Ke správě profilu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> je potřeba aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ano"</string> - <string name="consent_no" msgid="1335543792857823917">"Ne, díky"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml index 5a31f9bba4b6..bc67948c3ecf 100644 --- a/packages/CompanionDeviceManager/res/values-da/strings.xml +++ b/packages/CompanionDeviceManager/res/values-da/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Vælg den enhed (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), som skal administreres af <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string> <string name="profile_name_watch" msgid="576290739483672360">"ur"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Angiv <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> til administration af: <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> er nødvendig for at administrere: <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> - <string name="consent_no" msgid="1335543792857823917">"Nej tak"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml index b643eb2936ce..1c7ec74f4494 100644 --- a/packages/CompanionDeviceManager/res/values-de/strings.xml +++ b/packages/CompanionDeviceManager/res/values-de/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Gerät (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) auswählen, das von <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> verwaltet werden soll"</string> <string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string> <string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> zum Verwalten deines Geräts (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) festlegen – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist erforderlich, um dein Gerät (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) zu verwalten. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> - <string name="consent_no" msgid="1335543792857823917">"Nein danke"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml index 60de2ffe0572..fed516fb04eb 100644 --- a/packages/CompanionDeviceManager/res/values-el/strings.xml +++ b/packages/CompanionDeviceManager/res/values-el/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για διαχείριση από την εφαρμογή <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string> <string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Ορίστε μια εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> για διαχείριση του προφίλ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> απαιτείται για τη διαχείριση του προφίλ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ναι"</string> - <string name="consent_no" msgid="1335543792857823917">"Όχι, ευχαριστώ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml index 2fed1ae7fec3..4fd057f3e7e4 100644 --- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Set <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> - <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml index 2fed1ae7fec3..4fd057f3e7e4 100644 --- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Set <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> - <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml index 2fed1ae7fec3..4fd057f3e7e4 100644 --- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Set <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> - <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml index 2fed1ae7fec3..4fd057f3e7e4 100644 --- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Set <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> - <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml index f3c4b1dcb434..0e3902c50aea 100644 --- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Set <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> - <string name="consent_no" msgid="1335543792857823917">"No thanks"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml index 4fbb57ed9440..6b903c609fe9 100644 --- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para que <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> lo administre"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Configura <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> para administrar <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Se requiere <xliff:g id="APP_NAME">%1$s</xliff:g> para administrar tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Sí"</string> - <string name="consent_no" msgid="1335543792857823917">"No, gracias"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml index 5ca9305ce4d6..0a2906a97a39 100644 --- a/packages/CompanionDeviceManager/res/values-es/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para gestionarlo con <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Haz que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestione tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Se necesita <xliff:g id="APP_NAME">%1$s</xliff:g> para gestionar tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Sí"</string> - <string name="consent_no" msgid="1335543792857823917">"No, gracias"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml index 357f05237b85..4958a17206f7 100644 --- a/packages/CompanionDeviceManager/res/values-et/strings.xml +++ b/packages/CompanionDeviceManager/res/values-et/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Valige seade <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mida haldab rakendus <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string> <string name="profile_name_watch" msgid="576290739483672360">"käekell"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Määrake rakendus <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> haldama teie seadet <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> on vajalik teie seadme <xliff:g id="PROFILE_NAME">%2$s</xliff:g> haldamiseks. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Jah"</string> - <string name="consent_no" msgid="1335543792857823917">"Tänan, ei"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml index 14c7154acdd3..2a61fd519511 100644 --- a/packages/CompanionDeviceManager/res/values-eu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Aukeratu <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string> <string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Konfiguratu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>) kudea dezan"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> erabili behar duzu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> kudeatzeko. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Bai"</string> - <string name="consent_no" msgid="1335543792857823917">"Ez"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml index 6bb9620f09f7..8d102303d91a 100644 --- a/packages/CompanionDeviceManager/res/values-fa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای مدیریت کردن با <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string> <string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string> - <string name="confirmation_title" msgid="4751119145078041732">"تنظیم <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> برای مدیریت کردن <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"برای مدیریت کردن <xliff:g id="PROFILE_NAME">%2$s</xliff:g> به <xliff:g id="APP_NAME">%1$s</xliff:g> نیاز دارید. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"بله"</string> - <string name="consent_no" msgid="1335543792857823917">"نه متشکرم"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml index 5a9c1cd66aa8..cfa03af870dc 100644 --- a/packages/CompanionDeviceManager/res/values-fi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, jota <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> hallinnoi"</string> <string name="profile_name_generic" msgid="6851028682723034988">"laite"</string> <string name="profile_name_watch" msgid="576290739483672360">"kello"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Aseta <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> profiilin (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) hallinnoijaksi – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> tarvitaan profiilin (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) hallinnointiin. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Kyllä"</string> - <string name="consent_no" msgid="1335543792857823917">"Ei kiitos"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml index b31babda1a00..d3cfc299c4ce 100644 --- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Choisissez un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré par <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string> <string name="profile_name_watch" msgid="576290739483672360">"montre"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Utiliser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"L\'application <xliff:g id="APP_NAME">%1$s</xliff:g> est requise pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Oui"</string> - <string name="consent_no" msgid="1335543792857823917">"Non merci"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml index 08c93a2c31c6..d82e3905c5d1 100644 --- a/packages/CompanionDeviceManager/res/values-fr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Sélectionner le/la <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string> <string name="profile_name_watch" msgid="576290739483672360">"montre"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Définir <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pour la gestion de votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> est requis pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Oui"</string> - <string name="consent_no" msgid="1335543792857823917">"Non, merci"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml index c95b90e73edc..2a85398cf3cc 100644 --- a/packages/CompanionDeviceManager/res/values-gl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Escolle un perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) para que o xestione a aplicación <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Define a aplicación <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> para a xestión do teu perfil (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>): <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Necesítase a aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> para xestionar o teu perfil (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>). <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Si"</string> - <string name="consent_no" msgid="1335543792857823917">"Non, grazas"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml index 7e4104208446..6f52403ed416 100644 --- a/packages/CompanionDeviceManager/res/values-gu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string> <string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string> - <string name="confirmation_title" msgid="4751119145078041732">"તમારા <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>ને મેનેજ કરવા માટે <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> સેટ કરો"</string> - <string name="profile_summary" msgid="2009764182871566255">"તમારા <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ને મેનેજ કરવા માટે <xliff:g id="APP_NAME">%1$s</xliff:g> જરૂરી છે. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"હા"</string> - <string name="consent_no" msgid="1335543792857823917">"ના, આભાર"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml index ac95cc620bfa..9af99924c76a 100644 --- a/packages/CompanionDeviceManager/res/values-hi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें, ताकि उसे <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> की मदद से प्रबंधित किया जा सके"</string> <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string> <string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string> - <string name="confirmation_title" msgid="4751119145078041732">"अपने <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> को प्रबंधित करने के लिए, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को सेट करें"</string> - <string name="profile_summary" msgid="2009764182871566255">"आपके <xliff:g id="PROFILE_NAME">%2$s</xliff:g> को प्रबंधित करने के लिए, <xliff:g id="APP_NAME">%1$s</xliff:g> की ज़रूरत है. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"हां"</string> - <string name="consent_no" msgid="1335543792857823917">"नहीं, रहने दें"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml index df8451f5f127..fe30ec485169 100644 --- a/packages/CompanionDeviceManager/res/values-hr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="profile_name_watch" msgid="576290739483672360">"satom"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Postavite aplikaciju <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja vašim profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g> –- <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> potrebna je za upravljanje vašim <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Da"</string> - <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml index ff1c6c54d7ba..370d4dff6a98 100644 --- a/packages/CompanionDeviceManager/res/values-hu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"A(z) <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> alkalmazással kezelni kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiválasztása"</string> <string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string> <string name="profile_name_watch" msgid="576290739483672360">"óra"</string> - <string name="confirmation_title" msgid="4751119145078041732">"A(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazás beállítása a(z) <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>) kezelésére"</string> - <string name="profile_summary" msgid="2009764182871566255">"Szükség van a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazásra a(z) <xliff:g id="PROFILE_NAME">%2$s</xliff:g> kezeléséhez. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Igen"</string> - <string name="consent_no" msgid="1335543792857823917">"Nem"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml index 194223d1d416..fee55d0c5396 100644 --- a/packages/CompanionDeviceManager/res/values-hy/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը, որը պետք է կառավարվի <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> հավելվածի կողմից"</string> <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string> <string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Ընտրեք <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածը որպես <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ի կառավարիչ․ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Ձեր <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ը կառավարելու համար անհրաժեշտ է <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը։ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Այո"</string> - <string name="consent_no" msgid="1335543792857823917">"Ոչ, շնորհակալություն"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml index 58bf3cb4bca4..498bf2cd3351 100644 --- a/packages/CompanionDeviceManager/res/values-in/strings.xml +++ b/packages/CompanionDeviceManager/res/values-in/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk dikelola oleh <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string> <string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Tetapkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengelola <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Perlu <xliff:g id="APP_NAME">%1$s</xliff:g> untuk mengelola <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ya"</string> - <string name="consent_no" msgid="1335543792857823917">"Tidak"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml index cc5b98939b71..bd12658284ef 100644 --- a/packages/CompanionDeviceManager/res/values-is/strings.xml +++ b/packages/CompanionDeviceManager/res/values-is/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Velja <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sem <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> á að stjórna"</string> <string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string> <string name="profile_name_watch" msgid="576290739483672360">"úr"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> stjórn á <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> er krafist til að stjórna <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Já"</string> - <string name="consent_no" msgid="1335543792857823917">"Nei, takk"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml index 4cbefd801187..40d43207bced 100644 --- a/packages/CompanionDeviceManager/res/values-it/strings.xml +++ b/packages/CompanionDeviceManager/res/values-it/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> che sia gestito da <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"orologio"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Configura <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> per gestire il tuo <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"È richiesta l\'app <xliff:g id="APP_NAME">%1$s</xliff:g> per gestire il tuo <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Sì"</string> - <string name="consent_no" msgid="1335543792857823917">"No, grazie"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml index 8663e56ecf14..807cdd471642 100644 --- a/packages/CompanionDeviceManager/res/values-iw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"בחירה של <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string> <string name="profile_name_watch" msgid="576290739483672360">"שעון"</string> - <string name="confirmation_title" msgid="4751119145078041732">"הגדרה של <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לניהול <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> נדרשת לניהול של <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"כן"</string> - <string name="consent_no" msgid="1335543792857823917">"לא תודה"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml index ca17336bfb23..92022be9fade 100644 --- a/packages/CompanionDeviceManager/res/values-ja/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string> <string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string> <string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> で <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> を管理するよう設定する"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> を管理するために <xliff:g id="APP_NAME">%1$s</xliff:g> が必要です。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"はい"</string> - <string name="consent_no" msgid="1335543792857823917">"いいえ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml index 300c94f63cbe..64a79b48ec7e 100644 --- a/packages/CompanionDeviceManager/res/values-ka/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, რომელიც უნდა მართოს <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>-მა"</string> <string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string> <string name="profile_name_watch" msgid="576290739483672360">"საათი"</string> - <string name="confirmation_title" msgid="4751119145078041732">"დააყენეთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>, რომ მართოს თქვენი <xliff:g id="PROFILE_NAME">%2$s</xliff:g> — <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"თქვენი <xliff:g id="PROFILE_NAME">%2$s</xliff:g>-ის სამართავად საჭიროა <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"დიახ"</string> - <string name="consent_no" msgid="1335543792857823917">"არა, გმადლობთ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml index 94d6c3ed2d5f..edd5c0ee9cd0 100644 --- a/packages/CompanionDeviceManager/res/values-kk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> арқылы басқарылатын <xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын таңдаңыз"</string> <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string> <string name="profile_name_watch" msgid="576290739483672360">"сағат"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) құрылғысын басқаруға рұқсат беру"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> құрылғысын басқару үшін <xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы керек. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Иә"</string> - <string name="consent_no" msgid="1335543792857823917">"Жоқ, рақмет"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml index db13fe7884af..36c02de6790d 100644 --- a/packages/CompanionDeviceManager/res/values-km/strings.xml +++ b/packages/CompanionDeviceManager/res/values-km/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីឱ្យស្ថិតក្រោមការគ្រប់គ្រងរបស់ <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string> <string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string> - <string name="confirmation_title" msgid="4751119145078041732">"កំណត់ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ដើម្បីគ្រប់គ្រង <xliff:g id="PROFILE_NAME">%2$s</xliff:g> របស់អ្នក - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"ចាំបាច់ត្រូវមាន <xliff:g id="APP_NAME">%1$s</xliff:g> ដើម្បីគ្រប់គ្រង <xliff:g id="PROFILE_NAME">%2$s</xliff:g> របស់អ្នក។ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"បាទ/ចាស"</string> - <string name="consent_no" msgid="1335543792857823917">"ទេ អរគុណ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml index 0225166849fd..56c1557e5fef 100644 --- a/packages/CompanionDeviceManager/res/values-kn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string> <string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string> - <string name="confirmation_title" msgid="4751119145078041732">"ನಿಮ್ಮ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ಅನ್ನು ನಿರ್ವಹಿಸಲು, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಅನ್ನು ನಿರ್ವಹಿಸಿ"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು, <xliff:g id="APP_NAME">%1$s</xliff:g> ಅಗತ್ಯವಿದೆ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"ಹೌದು"</string> - <string name="consent_no" msgid="1335543792857823917">"ಬೇಡ, ಧನ್ಯವಾದಗಳು"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml index 1363e57e39a3..79c36dd017fa 100644 --- a/packages/CompanionDeviceManager/res/values-ko/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>에서 관리할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g>을(를) 선택"</string> <string name="profile_name_generic" msgid="6851028682723034988">"기기"</string> <string name="profile_name_watch" msgid="576290739483672360">"시계"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <xliff:g id="PROFILE_NAME">%2$s</xliff:g>(<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>)을(를) 관리하도록 설정"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> 프로필을 관리하려면 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱이 필요합니다. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"예"</string> - <string name="consent_no" msgid="1335543792857823917">"취소"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml index c01e2350aa04..8a90b3dc7d6a 100644 --- a/packages/CompanionDeviceManager/res/values-ky/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> тарабынан башкарылсын"</string> <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string> <string name="profile_name_watch" msgid="576290739483672360">"саат"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> түзмөгүңүздү башкарсын"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> профилиңизди башкаруу үчүн <xliff:g id="APP_NAME">%1$s</xliff:g> керек. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ооба"</string> - <string name="consent_no" msgid="1335543792857823917">"Жок, рахмат"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml index 68218dd79c50..a6564b347651 100644 --- a/packages/CompanionDeviceManager/res/values-lo/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ເພື່ອໃຫ້ຖືກຈັດການໂດຍ <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string> <string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string> - <string name="confirmation_title" msgid="4751119145078041732">"ຕັ້ງ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ເພື່ອຈັດການ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ຂອງທ່ານ"</string> - <string name="profile_summary" msgid="2009764182871566255">"ຕ້ອງໃຊ້ <xliff:g id="APP_NAME">%1$s</xliff:g> ເພື່ອຈັດການ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ຂອງທ່ານ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"ແມ່ນແລ້ວ"</string> - <string name="consent_no" msgid="1335543792857823917">"ບໍ່, ຂອບໃຈ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml index 5fd8280affca..382f1cf69a2d 100644 --- a/packages/CompanionDeviceManager/res/values-lt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, kurį valdys <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> (pasirinkite)"</string> <string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string> <string name="profile_name_watch" msgid="576290739483672360">"laikrodis"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Nustatyti, kad <xliff:g id="PROFILE_NAME">%2$s</xliff:g> <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> būtų valdomas programos <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Norint valdyti jūsų <xliff:g id="PROFILE_NAME">%2$s</xliff:g>, reikalinga programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Taip"</string> - <string name="consent_no" msgid="1335543792857823917">"Ne, ačiū"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml index bf036ec70d73..8d70bf788e27 100644 --- a/packages/CompanionDeviceManager/res/values-lv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) izvēle, ko pārvaldīt lietotnē <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string> <string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Lietotnes <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> iestatīšana profila (<xliff:g id="PROFILE_NAME">%2$s</xliff:g> — <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>) pārvaldībai"</string> - <string name="profile_summary" msgid="2009764182871566255">"Lai pārvaldītu profilu (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>), nepieciešama lietotne <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Jā"</string> - <string name="consent_no" msgid="1335543792857823917">"Nē, paldies"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml index 427ca8f940a0..5322e98c37b7 100644 --- a/packages/CompanionDeviceManager/res/values-mk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> со којшто ќе управува <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"уред"</string> <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Поставете ја <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управува со <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> е потребна за да управува со <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Да"</string> - <string name="consent_no" msgid="1335543792857823917">"Не, фала"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml index a48c45f73ae7..a9262c7973fb 100644 --- a/packages/CompanionDeviceManager/res/values-ml/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string> <string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string> - <string name="confirmation_title" msgid="4751119145078041732">"നിങ്ങളുടെ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> മാനേജ് ചെയ്യുന്നതിന് <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> സജ്ജീകരിക്കുക - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്ന ആപ്പിന് നിങ്ങളുടെ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> മാനേജ് ചെയ്യേണ്ടതുണ്ട്. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"വേണം"</string> - <string name="consent_no" msgid="1335543792857823917">"വേണ്ട"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml index 7ac20e613185..303286466f4b 100644 --- a/packages/CompanionDeviceManager/res/values-mn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>-н удирдах<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г сонгоно уу"</string> <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string> <string name="profile_name_watch" msgid="576290739483672360">"цаг"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>-аа удирдахын тулд <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-г тохируулна уу - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Таны <xliff:g id="PROFILE_NAME">%2$s</xliff:g>-г удирдахын тулд <xliff:g id="APP_NAME">%1$s</xliff:g> шаардлагатай. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Тийм"</string> - <string name="consent_no" msgid="1335543792857823917">"Үгүй, баярлалаа"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml index 144698b9bc4e..01dae7d3a21e 100644 --- a/packages/CompanionDeviceManager/res/values-mr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string> <string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string> <string name="profile_name_watch" msgid="576290739483672360">"पाहा"</string> - <string name="confirmation_title" msgid="4751119145078041732">"तुमची <xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापित करण्यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> सेट करा - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"तुमची <xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापित करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> आवश्यक आहे. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"होय"</string> - <string name="consent_no" msgid="1335543792857823917">"नाही, नको"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml index 7bea2c91fd2d..4e0f58bc2653 100644 --- a/packages/CompanionDeviceManager/res/values-ms/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string> <string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Tetapkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengurus <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> anda"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> diperlukan untuk mengurus <xliff:g id="PROFILE_NAME">%2$s</xliff:g> anda. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ya"</string> - <string name="consent_no" msgid="1335543792857823917">"Tidak perlu"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml index 9c2783cdcbbb..050c8ce4364a 100644 --- a/packages/CompanionDeviceManager/res/values-my/strings.xml +++ b/packages/CompanionDeviceManager/res/values-my/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> က စီမံခန့်ခွဲရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးချယ်ပါ"</string> <string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string> <string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string> - <string name="confirmation_title" msgid="4751119145078041732">"သင်၏ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ကို စီမံခန့်ခွဲရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကို သတ်မှတ်ပါ"</string> - <string name="profile_summary" msgid="2009764182871566255">"သင်၏ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ကို စီမံခန့်ခွဲရန် <xliff:g id="APP_NAME">%1$s</xliff:g> ကို လိုအပ်ပါသည်။ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> - <string name="consent_no" msgid="1335543792857823917">"မလိုပါ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml index 26fbb0350edc..a8e22033faed 100644 --- a/packages/CompanionDeviceManager/res/values-nb/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal administreres av <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string> <string name="profile_name_watch" msgid="576290739483672360">"klokke"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Angi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> for å administrere <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> kreves for å administrere <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> - <string name="consent_no" msgid="1335543792857823917">"Nei takk"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml index f289b3780672..45bfb5f469ee 100644 --- a/packages/CompanionDeviceManager/res/values-ne/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"आफूले <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> प्रयोग गरी व्यवस्थापन गर्न चाहेको <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चयन गर्नुहोस्"</string> <string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string> <string name="profile_name_watch" msgid="576290739483672360">"घडी"</string> - <string name="confirmation_title" msgid="4751119145078041732">"आफ्नो <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> व्यवस्थापन गर्न <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> तोक्नुहोस्"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापन गर्न <xliff:g id="APP_NAME">%1$s</xliff:g> इन्स्टल गर्नु पर्ने हुन्छ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"अँ"</string> - <string name="consent_no" msgid="1335543792857823917">"सहमत छुइनँ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml index 0c9cdffd4e17..e7e03904843e 100644 --- a/packages/CompanionDeviceManager/res/values-nl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string> <string name="profile_name_watch" msgid="576290739483672360">"horloge"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> instellen om je <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> te beheren"</string> - <string name="profile_summary" msgid="2009764182871566255">"Je hebt <xliff:g id="APP_NAME">%1$s</xliff:g> nodig om je <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te beheren. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> - <string name="consent_no" msgid="1335543792857823917">"Nee, bedankt"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml index c8c680f8f3a9..1f516fa4c0d0 100644 --- a/packages/CompanionDeviceManager/res/values-or/strings.xml +++ b/packages/CompanionDeviceManager/res/values-or/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string> <string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string> - <string name="confirmation_title" msgid="4751119145078041732">"ଆପଣଙ୍କ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ସେଟ୍ କରନ୍ତୁ - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"ଆପଣଙ୍କ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆବଶ୍ୟକ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"ହଁ"</string> - <string name="consent_no" msgid="1335543792857823917">"ନା, ଧନ୍ୟବାଦ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml index 0da94105a576..03693dc74274 100644 --- a/packages/CompanionDeviceManager/res/values-pa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string> <string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡਾ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਸੈੱਟ ਕਰੋ"</string> - <string name="profile_summary" msgid="2009764182871566255">"ਤੁਹਾਡੇ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ <xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਲੋੜ ਹੈ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"ਹਾਂ"</string> - <string name="consent_no" msgid="1335543792857823917">"ਨਹੀਂ ਧੰਨਵਾਦ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml index b07af57a936a..7adf064e80b6 100644 --- a/packages/CompanionDeviceManager/res/values-pl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, którym ma zarządzać aplikacja <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string> <string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Ustaw aplikację <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> do zarządzania profilem <xliff:g id="PROFILE_NAME">%2$s</xliff:g> na urządzeniu <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest wymagana do zarządzania profilem <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Tak"</string> - <string name="consent_no" msgid="1335543792857823917">"Nie, dziękuję"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml index 16906f62f9f1..b5ddc6db6f78 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Defina o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> como gerenciador do seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>)"</string> - <string name="profile_summary" msgid="2009764182871566255">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Sim"</string> - <string name="consent_no" msgid="1335543792857823917">"Agora não"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml index 745d1630dd86..c06ac7de1c11 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerido pela app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Defina a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> para gerir o seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> é necessária para gerir o seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Sim"</string> - <string name="consent_no" msgid="1335543792857823917">"Não, obrigado"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml index 16906f62f9f1..b5ddc6db6f78 100644 --- a/packages/CompanionDeviceManager/res/values-pt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Defina o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> como gerenciador do seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>)"</string> - <string name="profile_summary" msgid="2009764182871566255">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Sim"</string> - <string name="consent_no" msgid="1335543792857823917">"Agora não"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml index 187cfbdfe6f0..437e8dc78c76 100644 --- a/packages/CompanionDeviceManager/res/values-ro/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Alegeți un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string> <string name="profile_name_watch" msgid="576290739483672360">"ceas"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Setați <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pentru a vă gestiona profilul <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> este necesară pentru a vă gestiona profilul <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Da"</string> - <string name="consent_no" msgid="1335543792857823917">"Nu, mulțumesc"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml index 8dd9a392712b..d087959971b6 100644 --- a/packages/CompanionDeviceManager/res/values-ru/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Выберите устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), которым будет управлять приложение <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string> <string name="profile_name_watch" msgid="576290739483672360">"часы"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Разрешите приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> управлять устройством <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>)"</string> - <string name="profile_summary" msgid="2009764182871566255">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" необходимо для управления устройством (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>). <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Да"</string> - <string name="consent_no" msgid="1335543792857823917">"Нет"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml index 9e7c02e0c0d9..365b6bfb3d2a 100644 --- a/packages/CompanionDeviceManager/res/values-si/strings.xml +++ b/packages/CompanionDeviceManager/res/values-si/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> මගින් කළමනාකරණය කරනු ලැබීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string> <string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string> <string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ඔබගේ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> කළමනාකරණය කිරීමට සකසන්න - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"ඔබගේ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> කළමනාකරණය කිරීමට <xliff:g id="APP_NAME">%1$s</xliff:g> අවශ්යයි. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"ඔව්"</string> - <string name="consent_no" msgid="1335543792857823917">"එපා, ස්තුතියි"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml index 55a47c2df427..d5c099a36424 100644 --- a/packages/CompanionDeviceManager/res/values-sk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý bude spravovať aplikácia <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string> <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Nastavte aplikáciu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>, aby spravovala profil <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Na správu profilu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> je potrebná aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Áno"</string> - <string name="consent_no" msgid="1335543792857823917">"Nie, vďaka"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml index 159afd543609..d855db1cea72 100644 --- a/packages/CompanionDeviceManager/res/values-sl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Izbira naprave <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ki jo bo upravljala aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string> <string name="profile_name_watch" msgid="576290739483672360">"ura"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Nastavitev aplikacije <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>, ki bo upravljala napravo <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Za upravljanje naprave <xliff:g id="PROFILE_NAME">%2$s</xliff:g> potrebujete aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Da"</string> - <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml index 6fa759c15905..7335446765da 100644 --- a/packages/CompanionDeviceManager/res/values-sq/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Zgjidh një profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> që do të menaxhohet nga <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string> <string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Cakto <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> që të menaxhojë profilin tënd <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Nevojitet <xliff:g id="APP_NAME">%1$s</xliff:g> për të menaxhuar profilin tënd të <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Po"</string> - <string name="consent_no" msgid="1335543792857823917">"Jo, faleminderit"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml index fdbbe8e668f5..f3f65e17101b 100644 --- a/packages/CompanionDeviceManager/res/values-sr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> којим ће управљати апликација <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string> <string name="profile_name_watch" msgid="576290739483672360">"сат"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Подесите апликацију <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управља профилом <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је неопходна за управљање профилом <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Да"</string> - <string name="consent_no" msgid="1335543792857823917">"Не, хвала"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml index bfd25162aec6..574166822006 100644 --- a/packages/CompanionDeviceManager/res/values-sv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för hantering av <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string> <string name="profile_name_watch" msgid="576290739483672360">"klocka"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Konfigurera <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> för att hantera din <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> krävs för att hantera din <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> - <string name="consent_no" msgid="1335543792857823917">"Nej tack"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml index 437ae7f332e8..357eb4a475b8 100644 --- a/packages/CompanionDeviceManager/res/values-sw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili idhibitiwe na <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string> <string name="profile_name_watch" msgid="576290739483672360">"saa"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Weka <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ili udhibiti <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yako - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> linahitajika ili kudhibiti <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yako. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ndiyo"</string> - <string name="consent_no" msgid="1335543792857823917">"Hapana"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml index 9b4a720a4863..651d9e276a7a 100644 --- a/packages/CompanionDeviceManager/res/values-ta/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ஆப்ஸ் நிர்வகிக்கக்கூடிய <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்ந்தெடுங்கள்"</string> <string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string> <string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ஐ நிர்வகிக்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அமையுங்கள்"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> ஐ நிர்வகிக்க <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் வேண்டும். <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"ஆம்"</string> - <string name="consent_no" msgid="1335543792857823917">"வேண்டாம்"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml index 6e785de583aa..9c3e334c9373 100644 --- a/packages/CompanionDeviceManager/res/values-te/strings.xml +++ b/packages/CompanionDeviceManager/res/values-te/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ద్వారా మేనేజ్ చేయబడటానికి ఒక <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string> <string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string> <string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string> - <string name="confirmation_title" msgid="4751119145078041732">"మీ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>ను మేనేజ్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను సెటప్ చేయండి"</string> - <string name="profile_summary" msgid="2009764182871566255">"మీ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ను మేనేజ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అవసరం ఉంది. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"అవును"</string> - <string name="consent_no" msgid="1335543792857823917">"వద్దు, ధన్యవాదాలు"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml index b727d42035dd..557515af6ac8 100644 --- a/packages/CompanionDeviceManager/res/values-th/strings.xml +++ b/packages/CompanionDeviceManager/res/values-th/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะให้มีการจัดการโดย <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string> <string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string> - <string name="confirmation_title" msgid="4751119145078041732">"ตั้งค่า <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ให้จัดการ<xliff:g id="PROFILE_NAME">%2$s</xliff:g>ของคุณ - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"ต้องใช้ <xliff:g id="APP_NAME">%1$s</xliff:g> ในการจัดการ<xliff:g id="PROFILE_NAME">%2$s</xliff:g> <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"ใช่"</string> - <string name="consent_no" msgid="1335543792857823917">"ไม่เป็นไร"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml index a93282a8fae0..6cbf2e875881 100644 --- a/packages/CompanionDeviceManager/res/values-tl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para pamahalaan ng <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"relo"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Itakda ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> para pamahalaan ang iyong <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Kailangan ang <xliff:g id="APP_NAME">%1$s</xliff:g> para pamahalaan ang iyong <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Oo"</string> - <string name="consent_no" msgid="1335543792857823917">"Huwag na lang"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml index 3abe064d60bc..bc1ab31d9b90 100644 --- a/packages/CompanionDeviceManager/res/values-tr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> tarafından yönetilecek bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string> <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string> <string name="profile_name_watch" msgid="576290739483672360">"saat"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasını, <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> cihazınızı yönetecek şekilde ayarlayın"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yönetimi için gereklidir. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Evet"</string> - <string name="consent_no" msgid="1335543792857823917">"Hayır, teşekkürler"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml index 161d95e127e8..33477c8f1429 100644 --- a/packages/CompanionDeviceManager/res/values-uk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, яким керуватиме додаток <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string> <string name="profile_name_watch" msgid="576290739483672360">"годинник"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Налаштуйте додаток <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>, щоб керувати своїм пристроєм <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>)"</string> - <string name="profile_summary" msgid="2009764182871566255">"Щоб керувати своїм пристроєм (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>), вам потрібен додаток <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Так"</string> - <string name="consent_no" msgid="1335543792857823917">"Ні, дякую"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml index dce18152dff4..83e20d8940cd 100644 --- a/packages/CompanionDeviceManager/res/values-ur/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> کے ذریعے نظم کئے جانے کیلئے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو منتخب کریں"</string> <string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string> <string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string> - <string name="confirmation_title" msgid="4751119145078041732">"اپنے <xliff:g id="PROFILE_NAME">%2$s</xliff:g> کا نظم کرنے کے لیے <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو سیٹ کریں - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"آپ کے <xliff:g id="PROFILE_NAME">%2$s</xliff:g> کا نظم کرنے کے لیے <xliff:g id="APP_NAME">%1$s</xliff:g> کی ضرورت ہے۔ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"ہاں"</string> - <string name="consent_no" msgid="1335543792857823917">"نہیں شکریہ"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml index 2ca27b530651..b16db730def4 100644 --- a/packages/CompanionDeviceManager/res/values-uz/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string> <string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string> <string name="profile_name_watch" msgid="576290739483672360">"soat"</string> - <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> qurilmalarini boshqarish uchun <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasini sozlang"</string> - <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> qurilmasini boshqarish uchun <xliff:g id="APP_NAME">%1$s</xliff:g> zarur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Ha"</string> - <string name="consent_no" msgid="1335543792857823917">"Kerak emas"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml index 06a1ab6846ae..75d2de37cb14 100644 --- a/packages/CompanionDeviceManager/res/values-vi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> quản lý"</string> <string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string> <string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Đặt <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> để quản lý <xliff:g id="PROFILE_NAME">%2$s</xliff:g> của bạn – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"Cần có <xliff:g id="APP_NAME">%1$s</xliff:g> để quản lý <xliff:g id="PROFILE_NAME">%2$s</xliff:g> của bạn. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Có"</string> - <string name="consent_no" msgid="1335543792857823917">"Không, cảm ơn"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml index 12bfcf3629cd..788f8f9edce1 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"选择要由<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"设备"</string> <string name="profile_name_watch" msgid="576290739483672360">"手表"</string> - <string name="confirmation_title" msgid="4751119145078041732">"设为由<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>管理您的<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"若要管理<xliff:g id="PROFILE_NAME">%2$s</xliff:g>,您需要使用<xliff:g id="APP_NAME">%1$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"好"</string> - <string name="consent_no" msgid="1335543792857823917">"不用了"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml index 0c583b211035..576f3f46e8ba 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"選擇由 <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> 管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string> <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string> - <string name="confirmation_title" msgid="4751119145078041732">"設定 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 來管理您的 <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"必須使用 <xliff:g id="APP_NAME">%1$s</xliff:g> 來管理您的<xliff:g id="PROFILE_NAME">%2$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"是"</string> - <string name="consent_no" msgid="1335543792857823917">"不用了,謝謝"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml index 519f0e8a7082..8a50658ad25c 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」<strong></strong>管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string> <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string> - <string name="confirmation_title" msgid="4751119145078041732">"授權讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>管理你的<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"如要管理你的<xliff:g id="PROFILE_NAME">%2$s</xliff:g>,必須使用「<xliff:g id="APP_NAME">%1$s</xliff:g>」。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"是"</string> - <string name="consent_no" msgid="1335543792857823917">"不用了,謝謝"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml index 7721b54166f5..fc3f19d72ee2 100644 --- a/packages/CompanionDeviceManager/res/values-zu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml @@ -20,8 +20,12 @@ <string name="chooser_title" msgid="2262294130493605839">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ezophathwa yi-<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string> <string name="profile_name_watch" msgid="576290739483672360">"buka"</string> - <string name="confirmation_title" msgid="4751119145078041732">"Setha i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukuba iphathe i-<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> - <string name="profile_summary" msgid="2009764182871566255">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> iyadingeka ukuphatha i-<xliff:g id="PROFILE_NAME">%2$s</xliff:g> yakho. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> - <string name="consent_yes" msgid="4055438216605487056">"Yebo"</string> - <string name="consent_no" msgid="1335543792857823917">"Cha ngiyabonga"</string> + <!-- no translation found for confirmation_title (814973816731238955) --> + <skip /> + <!-- no translation found for profile_summary (2059360676631420073) --> + <skip /> + <!-- no translation found for consent_yes (8344487259618762872) --> + <skip /> + <!-- no translation found for consent_no (2640796915611404382) --> + <skip /> </resources> diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt index a8f1a4d2a7f8..243e4ca4295a 100644 --- a/packages/Connectivity/framework/api/current.txt +++ b/packages/Connectivity/framework/api/current.txt @@ -143,6 +143,7 @@ package android.net { public static class ConnectivityManager.NetworkCallback { ctor public ConnectivityManager.NetworkCallback(); + ctor public ConnectivityManager.NetworkCallback(int); method public void onAvailable(@NonNull android.net.Network); method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean); method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities); @@ -150,6 +151,7 @@ package android.net { method public void onLosing(@NonNull android.net.Network, int); method public void onLost(@NonNull android.net.Network); method public void onUnavailable(); + field public static final int FLAG_INCLUDE_LOCATION_INFO = 1; // 0x1 } public static interface ConnectivityManager.OnNetworkActiveListener { @@ -293,6 +295,7 @@ package android.net { method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier(); method public int getOwnerUid(); method public int getSignalStrength(); + method @NonNull public java.util.Set<java.lang.Integer> getSubIds(); method @Nullable public android.net.TransportInfo getTransportInfo(); method public boolean hasCapability(int); method public boolean hasTransport(int); @@ -399,6 +402,11 @@ package android.net { method public android.net.NetworkRequest.Builder removeTransportType(int); method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String); method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier); + method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>); + } + + public class ParseException extends java.lang.RuntimeException { + field public String response; } public class ProxyInfo implements android.os.Parcelable { diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt index 6df57c132382..4b3336644ef9 100644 --- a/packages/Connectivity/framework/api/module-lib-current.txt +++ b/packages/Connectivity/framework/api/module-lib-current.txt @@ -7,8 +7,9 @@ package android.net { public class ConnectivityManager { 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> getAllNetworkStateSnapshot(); + method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange(); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); - method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle); } diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt index a732430e6a9c..a98f14ea9408 100644 --- a/packages/Connectivity/framework/api/system-current.txt +++ b/packages/Connectivity/framework/api/system-current.txt @@ -296,6 +296,7 @@ package android.net { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int); method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int); method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String); + method @NonNull public android.net.NetworkCapabilities.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>); method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo); } diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java index bbf45596e789..7189be10d8f4 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java @@ -16,10 +16,10 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.IpSecManager.INVALID_RESOURCE_ID; import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST; import static android.net.NetworkRequest.Type.LISTEN; import static android.net.NetworkRequest.Type.REQUEST; +import static android.net.NetworkRequest.Type.TRACK_BEST; import static android.net.NetworkRequest.Type.TRACK_DEFAULT; import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT; import static android.net.QosCallback.QosCallbackRegistrationException; @@ -43,6 +43,7 @@ import android.net.SocketKeepalive.Callback; import android.net.TetheringManager.StartTetheringCallback; import android.net.TetheringManager.TetheringEventCallback; import android.net.TetheringManager.TetheringRequest; +import android.net.wifi.WifiNetworkSuggestion; import android.os.Binder; import android.os.Build; import android.os.Build.VERSION_CODES; @@ -1314,7 +1315,7 @@ public class ConnectivityManager { } /** - * Returns an array of {@link android.net.NetworkCapabilities} objects, representing + * Returns an array of {@link NetworkCapabilities} objects, representing * the Networks that applications run by the given user will use by default. * @hide */ @@ -1394,11 +1395,19 @@ public class ConnectivityManager { } /** - * Get the {@link android.net.NetworkCapabilities} for the given {@link Network}. This + * Get the {@link NetworkCapabilities} for the given {@link Network}. This * will return {@code null} if the network is unknown. * + * This will remove any location sensitive data in {@link TransportInfo} embedded in + * {@link NetworkCapabilities#getTransportInfo()}. Some transport info instances like + * {@link android.net.wifi.WifiInfo} contain location sensitive information. Retrieving + * this location sensitive information (subject to app's location permissions) will be + * noted by system. To include any location sensitive data in {@link TransportInfo}, + * use a {@link NetworkCallback} with + * {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} flag. + * * @param network The {@link Network} object identifying the network in question. - * @return The {@link android.net.NetworkCapabilities} for the network, or {@code null}. + * @return The {@link NetworkCapabilities} for the network, or {@code null}. */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable @@ -1996,7 +2005,7 @@ public class ConnectivityManager { dup = createInvalidFd(); } return new NattSocketKeepalive(mService, network, dup, - INVALID_RESOURCE_ID /* Unused */, source, destination, executor, callback); + -1 /* Unused */, source, destination, executor, callback); } /** @@ -3244,6 +3253,54 @@ public class ConnectivityManager { */ public static class NetworkCallback { /** + * No flags associated with this callback. + * @hide + */ + public static final int FLAG_NONE = 0; + /** + * Use this flag to include any location sensitive data in {@link NetworkCapabilities} sent + * via {@link #onCapabilitiesChanged(Network, NetworkCapabilities)}. + * <p> + * These include: + * <li> Some transport info instances (retrieved via + * {@link NetworkCapabilities#getTransportInfo()}) like {@link android.net.wifi.WifiInfo} + * contain location sensitive information. + * <li> OwnerUid (retrieved via {@link NetworkCapabilities#getOwnerUid()} is location + * sensitive for wifi suggestor apps (i.e using {@link WifiNetworkSuggestion}).</li> + * </p> + * <p> + * Note: + * <li> Retrieving this location sensitive information (subject to app's location + * permissions) will be noted by system. </li> + * <li> Without this flag any {@link NetworkCapabilities} provided via the callback does + * not include location sensitive info. + * </p> + */ + public static final int FLAG_INCLUDE_LOCATION_INFO = 1 << 0; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = "FLAG_", value = { + FLAG_NONE, + FLAG_INCLUDE_LOCATION_INFO + }) + public @interface Flag { } + + /** + * All the valid flags for error checking. + */ + private static final int VALID_FLAGS = FLAG_INCLUDE_LOCATION_INFO; + + public NetworkCallback() { + this(FLAG_NONE); + } + + public NetworkCallback(@Flag int flags) { + Preconditions.checkArgument((flags & VALID_FLAGS) == flags); + mFlags = flags; + } + + /** * Called when the framework connects to a new network to evaluate whether it satisfies this * request. If evaluation succeeds, this callback may be followed by an {@link #onAvailable} * callback. There is no guarantee that this new network will satisfy any requests, or that @@ -3380,7 +3437,7 @@ public class ConnectivityManager { * calling these methods while in a callback may return an outdated or even a null object. * * @param network The {@link Network} whose capabilities have changed. - * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this + * @param networkCapabilities The new {@link NetworkCapabilities} for this * network. */ public void onCapabilitiesChanged(@NonNull Network network, @@ -3449,6 +3506,7 @@ public class ConnectivityManager { public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {} private NetworkRequest networkRequest; + private final int mFlags; } /** @@ -3638,14 +3696,15 @@ public class ConnectivityManager { } Messenger messenger = new Messenger(handler); Binder binder = new Binder(); + final int callbackFlags = callback.mFlags; if (reqType == LISTEN) { request = mService.listenForNetwork( - need, messenger, binder, callingPackageName, + need, messenger, binder, callbackFlags, callingPackageName, getAttributionTag()); } else { request = mService.requestNetwork( need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType, - callingPackageName, getAttributionTag()); + callbackFlags, callingPackageName, getAttributionTag()); } if (request != null) { sCallbacks.put(request, callback); @@ -3692,7 +3751,7 @@ public class ConnectivityManager { } /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}. + * Request a network to satisfy a set of {@link NetworkCapabilities}. * * <p>This method will attempt to find the best network that matches the passed * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the @@ -3776,7 +3835,7 @@ public class ConnectivityManager { } /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}. + * Request a network to satisfy a set of {@link NetworkCapabilities}. * * This method behaves identically to {@link #requestNetwork(NetworkRequest, NetworkCallback)} * but runs all the callbacks on the passed Handler. @@ -3798,7 +3857,7 @@ public class ConnectivityManager { } /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited + * Request a network to satisfy a set of {@link NetworkCapabilities}, limited * by a timeout. * * This function behaves identically to the non-timed-out version @@ -3833,7 +3892,7 @@ public class ConnectivityManager { } /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited + * Request a network to satisfy a set of {@link NetworkCapabilities}, limited * by a timeout. * * This method behaves identically to @@ -3878,7 +3937,7 @@ public class ConnectivityManager { /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}. + * Request a network to satisfy a set of {@link NetworkCapabilities}. * * This function behaves identically to the version that takes a NetworkCallback, but instead * of {@link NetworkCallback} a {@link PendingIntent} is used. This means @@ -4190,6 +4249,18 @@ public class ConnectivityManager { } /** + * @hide + */ + // TODO: Make it public api. + @SuppressLint("ExecutorRegistration") + public void registerBestMatchingNetworkCallback(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { + final NetworkCapabilities nc = request.networkCapabilities; + final CallbackHandler cbHandler = new CallbackHandler(handler); + sendRequestForNetwork(nc, networkCallback, 0, TRACK_BEST, TYPE_NONE, cbHandler); + } + + /** * Requests bandwidth update for a given {@link Network} and returns whether the update request * is accepted by ConnectivityService. Once accepted, ConnectivityService will poll underlying * network connection for updated bandwidth information. The caller will be notified via @@ -4898,7 +4969,7 @@ public class ConnectivityManager { } /** - * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, but + * Request a network to satisfy a set of {@link NetworkCapabilities}, but * does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can * be used to request that the system provide a network without causing the network to be * in the foreground. @@ -4979,10 +5050,10 @@ public class ConnectivityManager { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK }) public void requestBackgroundNetwork(@NonNull NetworkRequest request, - @Nullable Handler handler, @NonNull NetworkCallback networkCallback) { + @NonNull Handler handler, @NonNull NetworkCallback networkCallback) { final NetworkCapabilities nc = request.networkCapabilities; sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST, - TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler)); + TYPE_NONE, new CallbackHandler(handler)); } /** @@ -5040,4 +5111,21 @@ public class ConnectivityManager { throw e.rethrowFromSystemServer(); } } + + // The first network ID of IPSec tunnel interface. + private static final int TUN_INTF_NETID_START = 0xFC00; + // The network ID range of IPSec tunnel interface. + private static final int TUN_INTF_NETID_RANGE = 0x0400; + + /** + * Get the network ID range reserved for IPSec tunnel interfaces. + * + * @return A Range which indicates the network ID range of IPSec tunnel interface. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + @NonNull + public static Range<Integer> getIpSecNetIdRange() { + return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1); + } } diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl index cd49258d1c47..f9393e315b83 100644 --- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl +++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl @@ -143,7 +143,7 @@ interface IConnectivityManager NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType, in Messenger messenger, int timeoutSec, in IBinder binder, int legacy, - String callingPackageName, String callingAttributionTag); + int callbackFlags, String callingPackageName, String callingAttributionTag); NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities, in PendingIntent operation, String callingPackageName, String callingAttributionTag); @@ -151,7 +151,7 @@ interface IConnectivityManager void releasePendingNetworkRequest(in PendingIntent operation); NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities, - in Messenger messenger, in IBinder binder, String callingPackageName, + in Messenger messenger, in IBinder binder, int callbackFlags, String callingPackageName, String callingAttributionTag); void pendingListenForNetwork(in NetworkCapabilities networkCapabilities, diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java index c82cd3b4f357..058f3c999dd7 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java +++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java @@ -25,6 +25,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.net.ConnectivityManager.NetworkCallback; +import android.net.wifi.WifiNetworkSuggestion; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -131,6 +132,7 @@ public final class NetworkCapabilities implements Parcelable { mPrivateDnsBroken = false; mRequestorUid = Process.INVALID_UID; mRequestorPackageName = null; + mSubIds = new ArraySet<>(); } /** @@ -159,6 +161,7 @@ public final class NetworkCapabilities implements Parcelable { mPrivateDnsBroken = nc.mPrivateDnsBroken; mRequestorUid = nc.mRequestorUid; mRequestorPackageName = nc.mRequestorPackageName; + mSubIds = new ArraySet<>(nc.mSubIds); } /** @@ -1048,6 +1051,16 @@ public final class NetworkCapabilities implements Parcelable { * * Instances of NetworkCapabilities sent to apps without the appropriate permissions will have * this field cleared out. + * + * <p> + * This field will only be populated for VPN and wifi network suggestor apps (i.e using + * {@link WifiNetworkSuggestion}), and only for the network they own. + * In the case of wifi network suggestors apps, this field is also location sensitive, so the + * app needs to hold {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission. If the + * app targets SDK version greater than or equal to {@link Build.VERSION_CODES#S}, then they + * also need to use {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} to get the info in their + * callback. The app will be blamed for location access if this field is included. + * </p> */ public int getOwnerUid() { return mOwnerUid; @@ -1655,6 +1668,7 @@ public final class NetworkCapabilities implements Parcelable { combineSSIDs(nc); combineRequestor(nc); combineAdministratorUids(nc); + combineSubIds(nc); } /** @@ -1674,8 +1688,9 @@ public final class NetworkCapabilities implements Parcelable { && satisfiedBySpecifier(nc) && (onlyImmutable || satisfiedBySignalStrength(nc)) && (onlyImmutable || satisfiedByUids(nc)) - && (onlyImmutable || satisfiedBySSID(nc))) - && (onlyImmutable || satisfiedByRequestor(nc)); + && (onlyImmutable || satisfiedBySSID(nc)) + && (onlyImmutable || satisfiedByRequestor(nc)) + && (onlyImmutable || satisfiedBySubIds(nc))); } /** @@ -1771,7 +1786,8 @@ public final class NetworkCapabilities implements Parcelable { && equalsOwnerUid(that) && equalsPrivateDnsBroken(that) && equalsRequestor(that) - && equalsAdministratorUids(that); + && equalsAdministratorUids(that) + && equalsSubIds(that); } @Override @@ -1793,7 +1809,8 @@ public final class NetworkCapabilities implements Parcelable { + Objects.hashCode(mPrivateDnsBroken) * 47 + Objects.hashCode(mRequestorUid) * 53 + Objects.hashCode(mRequestorPackageName) * 59 - + Arrays.hashCode(mAdministratorUids) * 61; + + Arrays.hashCode(mAdministratorUids) * 61 + + Objects.hashCode(mSubIds) * 67; } @Override @@ -1827,6 +1844,7 @@ public final class NetworkCapabilities implements Parcelable { dest.writeInt(mOwnerUid); dest.writeInt(mRequestorUid); dest.writeString(mRequestorPackageName); + dest.writeIntArray(CollectionUtils.toIntArray(mSubIds)); } public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR = @@ -1850,6 +1868,11 @@ public final class NetworkCapabilities implements Parcelable { netCap.mOwnerUid = in.readInt(); netCap.mRequestorUid = in.readInt(); netCap.mRequestorPackageName = in.readString(); + netCap.mSubIds = new ArraySet<>(); + final int[] subIdInts = Objects.requireNonNull(in.createIntArray()); + for (int i = 0; i < subIdInts.length; i++) { + netCap.mSubIds.add(subIdInts[i]); + } return netCap; } @Override @@ -1933,11 +1956,14 @@ public final class NetworkCapabilities implements Parcelable { sb.append(" SSID: ").append(mSSID); } - if (mPrivateDnsBroken) { sb.append(" PrivateDnsBroken"); } + if (!mSubIds.isEmpty()) { + sb.append(" SubscriptionIds: ").append(mSubIds); + } + sb.append("]"); return sb.toString(); } @@ -2251,6 +2277,67 @@ public final class NetworkCapabilities implements Parcelable { } /** + * Set of the subscription IDs that identifies the network or request, empty if none. + */ + @NonNull + private ArraySet<Integer> mSubIds = new ArraySet<>(); + + /** + * Sets the subscription ID set that associated to this network or request. + * + * @hide + */ + @NonNull + public NetworkCapabilities setSubIds(@NonNull Set<Integer> subIds) { + mSubIds = new ArraySet(Objects.requireNonNull(subIds)); + return this; + } + + /** + * Gets the subscription ID set that associated to this network or request. + * @return + */ + @NonNull + public Set<Integer> getSubIds() { + return new ArraySet<>(mSubIds); + } + + /** + * Tests if the subscription ID set of this network is the same as that of the passed one. + */ + private boolean equalsSubIds(@NonNull NetworkCapabilities nc) { + return Objects.equals(mSubIds, nc.mSubIds); + } + + /** + * Check if the subscription ID set requirements of this object are matched by the passed one. + * If specified in the request, the passed one need to have at least one subId and at least + * one of them needs to be in the request set. + */ + private boolean satisfiedBySubIds(@NonNull NetworkCapabilities nc) { + if (mSubIds.isEmpty()) return true; + if (nc.mSubIds.isEmpty()) return false; + for (final Integer subId : nc.mSubIds) { + if (mSubIds.contains(subId)) return true; + } + return false; + } + + /** + * Combine subscription ID set of the capabilities. + * + * <p>This is only legal if the subscription Ids are equal. + * + * <p>If both subscription IDs are not equal, they belong to different subscription + * (or no subscription). In this case, it would not make sense to add them together. + */ + private void combineSubIds(@NonNull NetworkCapabilities nc) { + if (!Objects.equals(mSubIds, nc.mSubIds)) { + throw new IllegalStateException("Can't combine two subscription ID sets"); + } + } + + /** * Builder class for NetworkCapabilities. * * This class is mainly for for {@link NetworkAgent} instances to use. Many fields in @@ -2556,6 +2643,18 @@ public final class NetworkCapabilities implements Parcelable { } /** + * Set the subscription ID set. + * + * @param subIds a set that represent the subscription IDs. Empty if clean up. + * @return this builder. + */ + @NonNull + public Builder setSubIds(@NonNull final Set<Integer> subIds) { + mCaps.setSubIds(subIds); + return this; + } + + /** * Builds the instance of the capabilities. * * @return the built instance of NetworkCapabilities. diff --git a/packages/Connectivity/framework/src/android/net/NetworkInfo.java b/packages/Connectivity/framework/src/android/net/NetworkInfo.java index d752901e2eb0..bb2349459331 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkInfo.java +++ b/packages/Connectivity/framework/src/android/net/NetworkInfo.java @@ -21,7 +21,6 @@ import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.Annotation.NetworkType; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; @@ -164,7 +163,7 @@ public class NetworkInfo implements Parcelable { * @param typeName a human-readable string for the network type, or an empty string or null. * @param subtypeName a human-readable string for the subtype, or an empty string or null. */ - public NetworkInfo(int type, @NetworkType int subtype, + public NetworkInfo(int type, int subtype, @Nullable String typeName, @Nullable String subtypeName) { if (!ConnectivityManager.isNetworkTypeValid(type) && type != ConnectivityManager.TYPE_NONE) { diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java index 17a8ee1720c4..3fd95ee58df2 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java +++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java @@ -114,6 +114,10 @@ public class NetworkRequest implements Parcelable { * for the network (if any) that satisfies the default Internet * request. * + * - TRACK_BEST, which causes the framework to send callbacks about + * the single, highest scoring current network (if any) that matches + * the specified NetworkCapabilities. + * * - BACKGROUND_REQUEST, like REQUEST but does not cause any networks * to retain the NET_CAPABILITY_FOREGROUND capability. A network with * no foreground requests is in the background. A network that has @@ -136,6 +140,7 @@ public class NetworkRequest implements Parcelable { REQUEST, BACKGROUND_REQUEST, TRACK_SYSTEM_DEFAULT, + TRACK_BEST, }; /** @@ -456,6 +461,21 @@ public class NetworkRequest implements Parcelable { } nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); } + + /** + * Sets the optional subscription ID set. + * <p> + * This specify the subscription IDs requirement. + * A network will satisfy this request only if it matches one of the subIds in this set. + * An empty set matches all networks, including those without a subId. + * + * @param subIds A {@code Set} that represents subscription IDs. + */ + @NonNull + public Builder setSubIds(@NonNull Set<Integer> subIds) { + mNetworkCapabilities.setSubIds(subIds); + return this; + } } // implement the Parcelable interface diff --git a/packages/Connectivity/framework/src/android/net/NetworkState.java b/packages/Connectivity/framework/src/android/net/NetworkState.java index d01026566ca0..9b69674728a8 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkState.java +++ b/packages/Connectivity/framework/src/android/net/NetworkState.java @@ -22,7 +22,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; -import android.util.Slog; +import android.util.Log; /** * Snapshot of network state. @@ -83,7 +83,7 @@ public class NetworkState implements Parcelable { if (VALIDATE_ROAMING_STATE && networkInfo != null && networkCapabilities != null) { if (networkInfo.isRoaming() == networkCapabilities .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) { - Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo + Log.wtf("NetworkState", "Roaming state disagreement between " + networkInfo + " and " + networkCapabilities); } } diff --git a/core/java/android/net/ParseException.java b/packages/Connectivity/framework/src/android/net/ParseException.java index bcfdd7ef09cc..bcfdd7ef09cc 100644 --- a/core/java/android/net/ParseException.java +++ b/packages/Connectivity/framework/src/android/net/ParseException.java diff --git a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java index d37c4691ddde..53d966937a70 100644 --- a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java +++ b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java @@ -92,7 +92,7 @@ public final class QosSocketInfo implements Parcelable { Objects.requireNonNull(socket, "socket cannot be null"); mNetwork = Objects.requireNonNull(network, "network cannot be null"); - mParcelFileDescriptor = ParcelFileDescriptor.dup(socket.getFileDescriptor$()); + mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket); mLocalSocketAddress = new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort()); } @@ -114,10 +114,10 @@ public final class QosSocketInfo implements Parcelable { try { return new InetSocketAddress(InetAddress.getByAddress(address), port); } catch (final UnknownHostException e) { - /* The catch block was purposely left empty. UnknownHostException will never be thrown + /* This can never happen. UnknownHostException will never be thrown since the address provided is numeric and non-null. */ + throw new RuntimeException("UnknownHostException on numeric address", e); } - return new InetSocketAddress(); } @Override diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp index 2fb9f72feab7..f630ceac3662 100644 --- a/packages/Connectivity/service/Android.bp +++ b/packages/Connectivity/service/Android.bp @@ -60,12 +60,14 @@ java_library { "services.core", "services.net", "unsupportedappusage", + "ServiceConnectivityResources", ], static_libs: [ "modules-utils-os", "net-utils-device-common", "net-utils-framework-common", "netd-client", + "PlatformProperties", ], apex_available: [ "//apex_available:platform", @@ -76,7 +78,7 @@ java_library { java_library { name: "service-connectivity", installable: true, - static_libs:[ + static_libs: [ "service-connectivity-pre-jarjar", ], jarjar_rules: "jarjar-rules.txt", diff --git a/packages/Connectivity/service/ServiceConnectivityResources/Android.bp b/packages/Connectivity/service/ServiceConnectivityResources/Android.bp new file mode 100644 index 000000000000..f2446b7f7eb8 --- /dev/null +++ b/packages/Connectivity/service/ServiceConnectivityResources/Android.bp @@ -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. +// + +// APK to hold all the wifi overlayable resources. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_app { + name: "ServiceConnectivityResources", + sdk_version: "system_current", + resource_dirs: [ + "res", + ], + privileged: true, + export_package_resources: true, + apex_available: [ + "com.android.tethering", + ], + // TODO: use a dedicated cert once generated + certificate: "platform", +} diff --git a/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.xml b/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.xml new file mode 100644 index 000000000000..2c303026158e --- /dev/null +++ b/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.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. + */ +--> +<!-- Manifest for connectivity resources APK --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.connectivity.resources" + coreApp="true" + android:versionCode="1" + android:versionName="S-initial"> + <application + android:label="@string/connectivityResourcesAppLabel" + android:defaultToDeviceProtectedStorage="true" + android:directBootAware="true"> + <!-- This is only used to identify this app by resolving the action. + The activity is never actually triggered. --> + <activity android:name="android.app.Activity" android:exported="true" android:enabled="true"> + <intent-filter> + <action android:name="com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml new file mode 100644 index 000000000000..7d98c76a40ba --- /dev/null +++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<!-- Configuration values for ConnectivityService + DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources + Overlay package following the overlayable.xml configuration in the same directory: + https://source.android.com/devices/architecture/rros --> +<resources> + + <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl. + If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + and if that value is empty, the framework will use a hard-coded default. + This is *NOT* a URL that will always be used by the system network validation to detect + captive portals: NetworkMonitor may use different strategies and will not necessarily use + this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays + instead. --> + <!--suppress CheckTagEmptyBody --> + <string translatable="false" name="config_networkCaptivePortalServerUrl"></string> + + <!-- The maximum duration (in milliseconds) we expect a network transition to take --> + <integer name="config_networkTransitionTimeout">60000</integer> + + <!-- Configuration of network interfaces that support WakeOnLAN --> + <string-array translatable="false" name="config_wakeonlan_supported_interfaces"> + <!-- + <item>wlan0</item> + <item>eth0</item> + --> + </string-array> + +</resources>
\ No newline at end of file diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml new file mode 100644 index 000000000000..00ec2df0e6f1 --- /dev/null +++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <overlayable name="ServiceConnectivityResourcesConfig"> + <policy type="product|system|vendor"> + <!-- Configuration values for ConnectivityService --> + <item type="string" name="config_networkCaptivePortalServerUrl"/> + <item type="integer" name="config_networkTransitionTimeout"/> + <item type="array" name="config_wakeonlan_supported_interfaces"/> + + + </policy> + </overlayable> +</resources> diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml new file mode 100644 index 000000000000..2c7b99265019 --- /dev/null +++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<resources> + <!-- The System Connectivity Resources package is an internal system package that provides + configuration values for system networking that were pre-configured in the device. This + is the name of the package to display in the list of system apps. [CHAR LIMIT=40] --> + <string name="connectivityResourcesAppLabel">System Connectivity Resources</string> +</resources>
\ No newline at end of file diff --git a/packages/Connectivity/service/jarjar-rules.txt b/packages/Connectivity/service/jarjar-rules.txt index d8c60a428ef6..a7b419b020b5 100644 --- a/packages/Connectivity/service/jarjar-rules.txt +++ b/packages/Connectivity/service/jarjar-rules.txt @@ -1,3 +1,4 @@ +rule android.sysprop.** com.android.connectivity.sysprop.@1 rule com.android.net.module.util.** com.android.connectivity.net-utils.@1 rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1 diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk Binary files differindex 180dfb672c7f..784a74701b4f 100644 --- a/packages/CtsShim/apk/arm/CtsShim.apk +++ b/packages/CtsShim/apk/arm/CtsShim.apk diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk Binary files differindex d87ea7fcef89..5b7bda4d4f84 100644 --- a/packages/CtsShim/apk/arm/CtsShimPriv.apk +++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk Binary files differindex 180dfb672c7f..784a74701b4f 100644 --- a/packages/CtsShim/apk/x86/CtsShim.apk +++ b/packages/CtsShim/apk/x86/CtsShim.apk diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk Binary files differindex 3124651fe425..780cb8a72526 100644 --- a/packages/CtsShim/apk/x86/CtsShimPriv.apk +++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index c1dca5df1b2f..16a946dc7bc6 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -138,9 +138,6 @@ public class DynamicSystemInstallationService extends Service private long mCurrentPartitionSize; private long mCurrentPartitionInstalledSize; - private boolean mJustCancelledByUser; - private boolean mKeepNotification; - // This is for testing only now private boolean mEnableWhenCompleted; @@ -174,11 +171,6 @@ public class DynamicSystemInstallationService extends Service if (cache != null) { cache.flush(); } - - if (!mKeepNotification) { - // Cancel the persistent notification. - mNM.cancel(NOTIFICATION_ID); - } } @Override @@ -231,9 +223,11 @@ public class DynamicSystemInstallationService extends Service return; } + boolean removeNotification = false; switch (result) { case RESULT_CANCELLED: postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null); + removeNotification = true; break; case RESULT_ERROR_IO: @@ -251,7 +245,7 @@ public class DynamicSystemInstallationService extends Service } // if it's not successful, reset the task and stop self. - resetTaskAndStop(); + resetTaskAndStop(removeNotification); } private void executeInstallCommand(Intent intent) { @@ -302,12 +296,12 @@ public class DynamicSystemInstallationService extends Service return; } - stopForeground(true); - mJustCancelledByUser = true; - if (mInstallTask.cancel(false)) { - // Will stopSelf() in onResult() + // onResult() would call resetTaskAndStop() upon task completion. Log.d(TAG, "Cancel request filed successfully"); + // Dismiss the notification as soon as possible as DynamicSystemManager.remove() may + // block. + stopForeground(STOP_FOREGROUND_REMOVE); } else { Log.e(TAG, "Trying to cancel installation while it's already completed."); } @@ -322,8 +316,7 @@ public class DynamicSystemInstallationService extends Service if (!isDynamicSystemInstalled() && (getStatus() != STATUS_READY)) { Log.e(TAG, "Trying to discard AOT while there is no complete installation"); // Stop foreground state and dismiss stale notification. - stopForeground(STOP_FOREGROUND_REMOVE); - resetTaskAndStop(); + resetTaskAndStop(true); return; } @@ -331,8 +324,8 @@ public class DynamicSystemInstallationService extends Service getString(R.string.toast_dynsystem_discarded), Toast.LENGTH_LONG).show(); - resetTaskAndStop(); postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null); + resetTaskAndStop(true); mDynSystem.remove(); } @@ -412,12 +405,13 @@ public class DynamicSystemInstallationService extends Service } private void resetTaskAndStop() { - mInstallTask = null; + resetTaskAndStop(/* removeNotification= */ false); + } - new Handler().postDelayed(() -> { - stopForeground(STOP_FOREGROUND_DETACH); - stopSelf(); - }, 50); + private void resetTaskAndStop(boolean removeNotification) { + mInstallTask = null; + stopForeground(removeNotification ? STOP_FOREGROUND_REMOVE : STOP_FOREGROUND_DETACH); + stopSelf(); } private void prepareNotification() { @@ -525,7 +519,7 @@ public class DynamicSystemInstallationService extends Service private void postStatus(int status, int cause, Throwable detail) { String statusString; String causeString; - mKeepNotification = false; + boolean notifyOnNotificationBar = true; switch (status) { case STATUS_NOT_STARTED: @@ -551,18 +545,16 @@ public class DynamicSystemInstallationService extends Service break; case CAUSE_INSTALL_CANCELLED: causeString = "INSTALL_CANCELLED"; + notifyOnNotificationBar = false; break; case CAUSE_ERROR_IO: causeString = "ERROR_IO"; - mKeepNotification = true; break; case CAUSE_ERROR_INVALID_URL: causeString = "ERROR_INVALID_URL"; - mKeepNotification = true; break; case CAUSE_ERROR_EXCEPTION: causeString = "ERROR_EXCEPTION"; - mKeepNotification = true; break; default: causeString = "CAUSE_NOT_SPECIFIED"; @@ -571,16 +563,6 @@ public class DynamicSystemInstallationService extends Service Log.d(TAG, "status=" + statusString + ", cause=" + causeString + ", detail=" + detail); - boolean notifyOnNotificationBar = true; - - if (status == STATUS_NOT_STARTED - && cause == CAUSE_INSTALL_CANCELLED - && mJustCancelledByUser) { - // if task is cancelled by user, do not notify them - notifyOnNotificationBar = false; - mJustCancelledByUser = false; - } - if (notifyOnNotificationBar) { mNM.notify(NOTIFICATION_ID, buildNotification(status, cause, detail)); } diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index 4ef5e2b4f090..59ea9f0150bf 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -320,7 +320,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } } - private void installScratch() throws IOException, InterruptedException { + private void installScratch() throws IOException { final long scratchSize = mDynSystem.suggestScratchSize(); Thread thread = new Thread() { @Override @@ -347,7 +347,11 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog publishProgress(progress); } - Thread.sleep(100); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // Ignore the error. + } } if (mInstallationSession == null) { @@ -361,7 +365,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } } - private void installUserdata() throws IOException, InterruptedException { + private void installUserdata() throws IOException { Thread thread = new Thread(() -> { mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false); }); @@ -383,7 +387,11 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog publishProgress(progress); } - Thread.sleep(100); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // Ignore the error. + } } if (mInstallationSession == null) { @@ -397,8 +405,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } } - private void installImages() - throws IOException, InterruptedException, ImageValidationException { + private void installImages() throws IOException, ImageValidationException { if (mStream != null) { if (mIsZip) { installStreamingZipUpdate(); @@ -410,14 +417,12 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } } - private void installStreamingGzUpdate() - throws IOException, InterruptedException, ImageValidationException { + private void installStreamingGzUpdate() throws IOException, ImageValidationException { Log.d(TAG, "To install a streaming GZ update"); installImage("system", mSystemSize, new GZIPInputStream(mStream)); } - private void installStreamingZipUpdate() - throws IOException, InterruptedException, ImageValidationException { + private void installStreamingZipUpdate() throws IOException, ImageValidationException { Log.d(TAG, "To install a streaming ZIP update"); ZipInputStream zis = new ZipInputStream(mStream); @@ -432,8 +437,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } } - private void installLocalZipUpdate() - throws IOException, InterruptedException, ImageValidationException { + private void installLocalZipUpdate() throws IOException, ImageValidationException { Log.d(TAG, "To install a local ZIP update"); Enumeration<? extends ZipEntry> entries = mZipFile.entries(); @@ -449,7 +453,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } private boolean installImageFromAnEntry(ZipEntry entry, InputStream is) - throws IOException, InterruptedException, ImageValidationException { + throws IOException, ImageValidationException { String name = entry.getName(); Log.d(TAG, "ZipEntry: " + name); @@ -473,7 +477,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } private void installImage(String partitionName, long uncompressedSize, InputStream is) - throws IOException, InterruptedException, ImageValidationException { + throws IOException, ImageValidationException { SparseInputStream sis = new SparseInputStream(new BufferedInputStream(is)); @@ -504,7 +508,11 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog return; } - Thread.sleep(100); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // Ignore the error. + } } if (mInstallationSession == null) { diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp index ed49bf4d5385..231babea97c2 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp @@ -20,4 +20,8 @@ android_library { ], sdk_version: "system_current", min_sdk_version: "21", + apex_available: [ + "//apex_available:platform", + "com.android.cellbroadcast", + ], } diff --git a/packages/SettingsLib/SettingsSpinner/res/drawable/arrow_drop_down_24dp.xml b/packages/SettingsLib/SettingsSpinner/res/drawable/arrow_drop_down.xml index 827d0b583388..054452629c88 100644 --- a/packages/SettingsLib/SettingsSpinner/res/drawable/arrow_drop_down_24dp.xml +++ b/packages/SettingsLib/SettingsSpinner/res/drawable/arrow_drop_down.xml @@ -16,11 +16,11 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:viewportWidth="24" - android:viewportHeight="24" + android:viewportWidth="18" + android:viewportHeight="18" android:width="24dp" android:height="24dp"> <path android:pathData="M7 10l5 5 5 -5z" - android:fillColor="?android:attr/textColorPrimary"/> -</vector>
\ No newline at end of file + android:fillColor="@android:color/black"/> +</vector> diff --git a/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml index 263c16b0749c..b38e3e3e89c1 100644 --- a/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml +++ b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml @@ -24,21 +24,21 @@ android:bottom="8dp"> <shape> <corners - android:radius="20dp"/> + android:radius="28dp"/> <solid - android:color="?android:attr/colorPrimary"/> + android:color="?android:attr/colorAccent"/> <stroke - android:color="#1f000000" + android:color="?android:attr/colorPrimary" android:width="1dp"/> <size - android:height="32dp"/> + android:height="@dimen/spinner_height"/> </shape> </item> <item android:gravity="center|end" - android:width="24dp" - android:height="24dp" - android:end="4dp" - android:drawable="@drawable/arrow_drop_down_24dp"/> + android:width="18dp" + android:height="18dp" + android:end="8dp" + android:drawable="@drawable/arrow_drop_down"/> </layer-list>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_dropdown_background.xml b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_dropdown_background.xml new file mode 100644 index 000000000000..8cac988632bc --- /dev/null +++ b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_dropdown_background.xml @@ -0,0 +1,33 @@ +<?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. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + + <item> + <shape> + <solid + android:color="?android:attr/colorAccent"/> + </shape> + </item> + + <item> + <shape> + <solid android:color="#BBFFFFFF"/> + </shape> + </item> + +</layer-list> diff --git a/packages/SettingsLib/SettingsSpinner/res/layout/settings_spinner_dropdown_view.xml b/packages/SettingsLib/SettingsSpinner/res/layout/settings_spinner_dropdown_view.xml new file mode 100644 index 000000000000..a342c840cfbe --- /dev/null +++ b/packages/SettingsLib/SettingsSpinner/res/layout/settings_spinner_dropdown_view.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/text1" + style="@style/SettingsSpinnerTitleBar" + android:gravity="center_vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/settings_spinner_dropdown_background"/> diff --git a/packages/SettingsLib/SettingsSpinner/res/layout/settings_spinner_view.xml b/packages/SettingsLib/SettingsSpinner/res/layout/settings_spinner_view.xml index bdd370fe04ee..75de34e86bc4 100644 --- a/packages/SettingsLib/SettingsSpinner/res/layout/settings_spinner_view.xml +++ b/packages/SettingsLib/SettingsSpinner/res/layout/settings_spinner_view.xml @@ -19,7 +19,5 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" style="@style/SettingsSpinnerTitleBar" - android:maxLines="1" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:ellipsize="marquee"/> + android:layout_height="wrap_content"/> diff --git a/packages/SystemUI/res/drawable/controls_dialog_bg.xml b/packages/SettingsLib/SettingsSpinner/res/values/dimens.xml index 1ccb176b8689..d526df6bedd4 100644 --- a/packages/SystemUI/res/drawable/controls_dialog_bg.xml +++ b/packages/SettingsLib/SettingsSpinner/res/values/dimens.xml @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2021 The Android Open Source Project +<!-- Copyright (C) 2021 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. --> -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <solid android:color="?android:attr/colorBackground" /> - <corners android:radius="@dimen/notification_corner_radius" /> -</shape> + +<resources> + <dimen name="spinner_height">36dp</dimen> + <dimen name="spinner_padding_top_or_bottom">8dp</dimen> +</resources> diff --git a/packages/SettingsLib/SettingsSpinner/res/values/styles.xml b/packages/SettingsLib/SettingsSpinner/res/values/styles.xml index 8af20e20ede9..f665f3836002 100644 --- a/packages/SettingsLib/SettingsSpinner/res/values/styles.xml +++ b/packages/SettingsLib/SettingsSpinner/res/values/styles.xml @@ -18,9 +18,13 @@ <resources> <style name="SettingsSpinnerTitleBar"> <item name="android:textAppearance">?android:attr/textAppearanceButton</item> + <item name="android:textColor">@android:color/black</item> + <item name="android:maxLines">1</item> + <item name="android:ellipsize">marquee</item> + <item name="android:minHeight">@dimen/spinner_height</item> <item name="android:paddingStart">16dp</item> <item name="android:paddingEnd">36dp</item> - <item name="android:paddingTop">8dp</item> - <item name="android:paddingBottom">8dp</item> + <item name="android:paddingTop">@dimen/spinner_padding_top_or_bottom</item> + <item name="android:paddingBottom">@dimen/spinner_padding_top_or_bottom</item> </style> -</resources>
\ No newline at end of file +</resources> diff --git a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java index 5ef8f7ac792b..0be80a9fd466 100644 --- a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java +++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java @@ -121,4 +121,11 @@ public class SettingsSpinner extends Spinner { int mode) { super(context, attrs, defStyleAttr, defStyleRes, mode, null); } -}
\ No newline at end of file + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + setDropDownVerticalOffset(getMeasuredHeight() - (int) getContext().getResources() + .getDimension(R.dimen.spinner_padding_top_or_bottom)); + } +} diff --git a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java index a8ca0d8664f3..83da512ce879 100644 --- a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java +++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java @@ -30,8 +30,7 @@ import com.android.settingslib.widget.R; public class SettingsSpinnerAdapter<T> extends ArrayAdapter<T> { private static final int DEFAULT_RESOURCE = R.layout.settings_spinner_view; - private static final int DFAULT_DROPDOWN_RESOURCE = - android.R.layout.simple_spinner_dropdown_item; + private static final int DFAULT_DROPDOWN_RESOURCE = R.layout.settings_spinner_dropdown_view; private final LayoutInflater mDefaultInflater; /** diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp index bda863a71453..73459c277df1 100644 --- a/packages/SettingsLib/SettingsTheme/Android.bp +++ b/packages/SettingsLib/SettingsTheme/Android.bp @@ -18,4 +18,8 @@ android_library { sdk_version: "system_current", min_sdk_version: "21", + apex_available: [ + "//apex_available:platform", + "com.android.cellbroadcast", + ], } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index ed2b6c92530b..e8e10a4def3e 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -153,6 +153,7 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.DOZE_TAP_SCREEN_GESTURE, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DOZE_WAKE_DISPLAY_GESTURE, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.DOZE_QUICK_PICKUP_GESTURE, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.NFC_PAYMENT_DEFAULT_COMPONENT, COMPONENT_NAME_VALIDATOR); VALIDATORS.put( Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN, NON_NEGATIVE_INTEGER_VALIDATOR); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index e427981b87d7..400742ba7d78 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -1937,8 +1937,11 @@ public class SettingsProvider extends ContentProvider { if (UserHandle.getAppId(Binder.getCallingUid()) < Process.FIRST_APPLICATION_UID) { return; } - checkReadableAnnotation(settingsType, settingName); ApplicationInfo ai = getCallingApplicationInfoOrThrow(); + if (ai.isSystemApp() || ai.isSignedWithPlatformKey()) { + return; + } + checkReadableAnnotation(settingsType, settingName); if (!ai.isInstantApp()) { return; } diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 4dc6d1475c4a..c520568a78e5 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -745,6 +745,7 @@ public class SettingsBackupTest { Settings.Secure.SILENCE_GESTURE, Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, + Settings.Secure.DOZE_QUICK_PICKUP_GESTURE, Settings.Secure.FACE_UNLOCK_RE_ENROLL, Settings.Secure.TAP_GESTURE, Settings.Secure.NEARBY_SHARING_COMPONENT, // not user configurable diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index a28a1e32a2a5..b4194fd5bbf9 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -426,6 +426,9 @@ <!-- Permission required for CTS test - ClipboardManagerTest --> <uses-permission android:name="android.permission.SET_CLIP_SOURCE" /> + <!-- Permission required for CTS test - FontManagerTest --> + <uses-permission android:name="android.permission.UPDATE_FONTS" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index b6d942a29d49..e0097df62078 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -578,7 +578,7 @@ <!-- People Space UI Screen --> <activity android:name=".people.PeopleSpaceActivity" - android:label="People" + android:label="@string/people_tile_title" android:enabled="true" android:exported="true" android:theme="@android:style/Theme.Material.NoActionBar"> @@ -592,7 +592,7 @@ <!-- People Space Widget --> <receiver android:name=".people.widget.PeopleSpaceWidgetProvider" - android:label="People Space" + android:label="@string/people_tile_title" android:enabled="true" android:exported="true"> <intent-filter> @@ -751,6 +751,17 @@ android:visibleToInstantApps="true"> </activity> + <activity android:name=".controls.ui.ControlsActivity" + android:label="@string/quick_controls_title" + android:theme="@style/Theme.ControlsActivity" + android:excludeFromRecents="true" + android:showWhenLocked="true" + android:showForAllUsers="true" + android:launchMode="singleInstance" + android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden" + android:visibleToInstantApps="true"> + </activity> + <receiver android:name=".controls.management.ControlsRequestReceiver" android:exported="true"> <intent-filter> 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 4fc197340e92..0d348e263545 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java @@ -44,7 +44,7 @@ public interface FalsingManager { /** * Returns true if the FalsingManager thinks the last gesure was not a valid tap. * - * Accepts one parameter, robustCheck, that distinctly changes behavior. When set to false, + * The first parameter, robustCheck, distinctly changes behavior. When set to false, * this method simply looks at the last gesture and returns whether it is a tap or not, (as * opposed to a swipe or other non-tap gesture). When set to true, a more thorough analysis * is performed that can include historical interactions and other contextual cues to see @@ -53,8 +53,11 @@ public interface FalsingManager { * Set robustCheck to true if you want to validate a tap for launching an action, like opening * a notification. Set to false if you simply want to know if the last gesture looked like a * tap. + * + * The second parameter, falsePenalty, indicates how much this should affect future gesture + * classifications if this tap looks like a false. */ - boolean isFalseTap(boolean robustCheck); + boolean isFalseTap(boolean robustCheck, double falsePenalty); /** * Returns true if the last two gestures do not look like a double tap. diff --git a/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml b/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml new file mode 100644 index 000000000000..34675ab891c1 --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_footer_action_chip_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_footer_action_inset" + android:insetBottom="@dimen/qs_footer_action_inset"> + <ripple + android:color="?android:attr/colorControlHighlight" + android:height="44dp"> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <solid android:color="@android:color/white"/> + <corners android:radius="@dimen/screenshot_button_corner_radius"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <stroke android:width="1dp" android:color="@color/qs_footer_action_border"/> + <solid android:color="@android:color/transparent"/> + <corners android:radius="@dimen/screenshot_button_corner_radius"/> + </shape> + </item> + </ripple> +</inset>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml b/packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml new file mode 100644 index 000000000000..596ed711dd43 --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml @@ -0,0 +1,35 @@ +<?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_footer_action_inset" + android:insetBottom="@dimen/qs_footer_action_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/screenshot_button_corner_radius"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <solid android:color="@android:color/transparent"/> + <corners android:radius="@dimen/screenshot_button_corner_radius"/> + </shape> + </item> + </ripple> +</inset>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml index aed067c30253..eef37ab20c69 100644 --- a/packages/SystemUI/res/layout/auth_biometric_contents.xml +++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml @@ -39,37 +39,34 @@ <Space android:id="@+id/space_above_icon" android:layout_width="match_parent" - android:layout_height="48dp" - android:visibility="visible" /> + android:layout_height="48dp" /> - <!-- Use a frame layout since certain biometrics (such as UDFPS) require the icon to be centered - within a certain area on the display. This makes it easy to 1) guarantee max size, and - 2) center the icon within the reserved area. --> - <FrameLayout android:id="@+id/biometric_icon_frame" + <FrameLayout + android:id="@+id/biometric_icon_frame" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal"> + <ImageView android:id="@+id/biometric_icon" android:layout_width="@dimen/biometric_dialog_biometric_icon_size" android:layout_height="@dimen/biometric_dialog_biometric_icon_size" android:layout_gravity="center" android:scaleType="fitXY" /> + </FrameLayout> - <!-- For sensors such as UDFPS, this view is used during custom measurement/layoutto add extra + <!-- For sensors such as UDFPS, this view is used during custom measurement/layout to add extra padding so that the biometric icon is always in the right physical position. --> <Space android:id="@+id/space_below_icon" android:layout_width="match_parent" - android:layout_height="0dp" - android:visibility="gone" /> + android:layout_height="12dp" /> <TextView android:id="@+id/indicator" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingHorizontal="24dp" - android:paddingVertical="12dp" android:textSize="12sp" android:gravity="center_horizontal" android:accessibilityLiveRegion="polite" @@ -84,6 +81,7 @@ style="?android:attr/buttonBarStyle" android:orientation="horizontal" android:paddingTop="16dp"> + <Space android:id="@+id/leftSpacer" android:layout_width="8dp" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/layout/controls_detail_dialog.xml b/packages/SystemUI/res/layout/controls_detail_dialog.xml index ee5315ad782f..28fc86372092 100644 --- a/packages/SystemUI/res/layout/controls_detail_dialog.xml +++ b/packages/SystemUI/res/layout/controls_detail_dialog.xml @@ -20,8 +20,8 @@ android:id="@+id/control_detail_root" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginTop="@dimen/controls_activity_view_top_offset" - android:orientation="vertical"> + android:orientation="vertical" + android:background="@android:color/black"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" @@ -30,7 +30,7 @@ <ImageView android:id="@+id/control_detail_close" android:contentDescription="@string/accessibility_desc_close" - android:src="@drawable/ic_close" + android:src="@drawable/ic_arrow_back" android:background="?android:attr/selectableItemBackgroundBorderless" android:tint="@color/control_primary_text" android:layout_width="48dp" @@ -56,7 +56,6 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" - android:background="@android:color/black" android:orientation="vertical" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/controls_in_dialog.xml b/packages/SystemUI/res/layout/controls_fullscreen.xml index 983999f9a5f8..1b2d2e2e9c89 100644 --- a/packages/SystemUI/res/layout/controls_in_dialog.xml +++ b/packages/SystemUI/res/layout/controls_fullscreen.xml @@ -20,11 +20,8 @@ android:id="@+id/control_detail_root" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginVertical="@dimen/controls_activity_view_top_offset" - android:layout_marginHorizontal="@dimen/controls_activity_view_side_offset" - android:padding="8dp" android:orientation="vertical" - android:background="@drawable/controls_dialog_bg"> + android:background="@android:color/black"> <com.android.systemui.globalactions.MinHeightScrollView android:layout_width="match_parent" diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml index b060afdc18e3..9d011482d011 100644 --- a/packages/SystemUI/res/layout/controls_with_favorites.xml +++ b/packages/SystemUI/res/layout/controls_with_favorites.xml @@ -25,8 +25,21 @@ <!-- make sure the header stays centered in the layout by adding a spacer --> <Space + android:id="@+id/controls_spacer" android:layout_width="@dimen/controls_header_menu_size" - android:layout_height="1dp" /> + android:layout_height="1dp" + android:visibility="gone" /> + + <ImageView + android:id="@+id/controls_close" + android:contentDescription="@string/accessibility_desc_close" + android:src="@drawable/ic_close" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:tint="@color/control_primary_text" + android:layout_width="@dimen/controls_header_menu_size" + android:layout_height="@dimen/controls_header_menu_size" + android:padding="12dp" + android:visibility="gone" /> <!-- need to keep this outer view in order to have a correctly sized anchor for the dropdown menu, as well as dropdown background in the right place --> <LinearLayout diff --git a/packages/SystemUI/res/layout/people_space_activity.xml b/packages/SystemUI/res/layout/people_space_activity.xml index 07af01b0db72..1784cae816ce 100644 --- a/packages/SystemUI/res/layout/people_space_activity.xml +++ b/packages/SystemUI/res/layout/people_space_activity.xml @@ -25,19 +25,30 @@ android:layout_height="wrap_content" android:layout_marginTop="16dp" android:orientation="vertical" - android:padding="16dp" + android:padding="24dp" android:clipChildren="false" android:clipToPadding="false"> <TextView + android:id="@+id/select_conversation_title" + android:gravity="center" + android:text="@string/select_conversation_title" + android:layout_width="wrap_content" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem" + android:textSize="24sp" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal"/> + + <TextView android:id="@+id/select_conversation" + android:gravity="center" android:text="@string/select_conversation_text" android:layout_width="match_parent" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem" - android:textSize="24sp" + android:textSize="16sp" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" - android:paddingBottom="16dp" /> + android:padding="24dp" /> </LinearLayout> </androidx.core.widget.NestedScrollView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/people_space_placeholder_layout.xml b/packages/SystemUI/res/layout/people_space_placeholder_layout.xml new file mode 100644 index 000000000000..3ced1ff6c74b --- /dev/null +++ b/packages/SystemUI/res/layout/people_space_placeholder_layout.xml @@ -0,0 +1,75 @@ +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + <LinearLayout + android:background="@drawable/people_space_tile_view_card" + android:id="@+id/item" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:orientation="horizontal" + android:gravity="center" + android:paddingVertical="2dp" + android:paddingHorizontal="8dp" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <ImageView + android:background="@drawable/ic_person" + android:id="@+id/person_icon_only" + android:layout_width="60dp" + android:layout_height="60dp"/> + + <LinearLayout + android:orientation="vertical" + android:paddingStart="8dp" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <ImageView + android:id="@+id/availability" + android:layout_width="10dp" + android:layout_height="10dp" + android:background="@drawable/circle_green_10dp"/> + <TextView + android:id="@+id/name" + android:text="@string/empty_user_name" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem" + android:textColor="?android:attr/textColorPrimary" + android:textSize="14sp" + android:maxLines="1" + android:ellipsize="end" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <TextView + android:id="@+id/last_interaction" + android:text="@string/empty_status" + android:textColor="?android:attr/textColorSecondary" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem" + android:textSize="12sp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:maxLines="3" + android:ellipsize="end"/> + </LinearLayout> + </LinearLayout> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/qs_carrier.xml index a5b8cfa5d60b..c521dc2b45a5 100644 --- a/packages/SystemUI/res/layout/qs_carrier.xml +++ b/packages/SystemUI/res/layout/qs_carrier.xml @@ -28,13 +28,6 @@ android:clipToPadding="false" android:focusable="true" > - <include - layout="@layout/mobile_signal_group" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/qs_carrier_margin_width" - android:visibility="gone" /> - <com.android.systemui.util.AutoMarqueeTextView android:id="@+id/qs_carrier_text" android:layout_width="wrap_content" @@ -46,4 +39,11 @@ android:singleLine="true" android:maxEms="7"/> + <include + layout="@layout/mobile_signal_group" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/qs_carrier_margin_width" + android:visibility="gone" /> + </com.android.systemui.qs.carrier.QSCarrier>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml index 93dd1a12f147..02179722b35c 100644 --- a/packages/SystemUI/res/layout/qs_footer_impl.xml +++ b/packages/SystemUI/res/layout/qs_footer_impl.xml @@ -89,7 +89,7 @@ android:background="?android:attr/selectableItemBackgroundBorderless" android:clickable="true" android:clipToPadding="false" - android:contentDescription="@string/accessibility_quick_settings_edit" + android:contentDescription="@string/accessibility_quick_settings_power_menu" android:focusable="true" android:padding="@dimen/qs_footer_icon_padding" android:src="@*android:drawable/ic_lock_power_off" diff --git a/packages/SystemUI/res/layout/qs_footer_impl_two_lines.xml b/packages/SystemUI/res/layout/qs_footer_impl_two_lines.xml new file mode 100644 index 000000000000..726e69f6e50c --- /dev/null +++ b/packages/SystemUI/res/layout/qs_footer_impl_two_lines.xml @@ -0,0 +1,159 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** Copyright 2021, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +--> + +<!-- Extends FrameLayout --> +<com.android.systemui.qs.QSFooterView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/qs_footer" + android:layout_width="match_parent" + android:layout_height="@dimen/qs_footer_height" + android:layout_marginStart="@dimen/qs_footer_margin" + android:layout_marginEnd="@dimen/qs_footer_margin" + android:background="@android:color/transparent" + android:baselineAligned="false" + android:clickable="false" + android:clipChildren="false" + android:clipToPadding="false"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="48dp" + android:layout_gravity="center_vertical"> + + <TextView + android:id="@+id/build" + android:layout_width="0dp" + android:layout_height="match_parent" + android:paddingStart="@dimen/qs_tile_margin_horizontal" + android:paddingEnd="4dp" + android:layout_weight="1" + android:clickable="true" + android:ellipsize="marquee" + android:focusable="true" + android:gravity="center_vertical" + android:singleLine="true" + android:textAppearance="@style/TextAppearance.QS.Status" + android:visibility="gone" /> + + <com.android.systemui.qs.PageIndicator + android:id="@+id/footer_page_indicator" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="center_vertical" + android:visibility="gone" /> + + <View + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/qs_footer_actions_container" + android:layout_width="match_parent" + android:layout_height="48dp" + android:gravity="center_vertical"> + + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:id="@android:id/edit" + android:layout_width="0dp" + android:layout_height="@dimen/qs_footer_action_button_size" + android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" + android:layout_weight="1" + android:background="@drawable/qs_footer_action_chip_background" + android:clickable="true" + android:clipToPadding="false" + android:contentDescription="@string/accessibility_quick_settings_edit" + android:focusable="true" + android:padding="@dimen/qs_footer_icon_padding" + android:src="@*android:drawable/ic_mode_edit" + android:tint="?android:attr/colorForeground" /> + + <com.android.systemui.statusbar.phone.MultiUserSwitch + android:id="@+id/multi_user_switch" + android:layout_width="0dp" + android:layout_height="@dimen/qs_footer_action_button_size" + android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" + android:layout_weight="1" + android:background="@drawable/qs_footer_action_chip_background" + android:focusable="true"> + + <ImageView + android:id="@+id/multi_user_avatar" + android:layout_width="@dimen/multi_user_avatar_expanded_size" + android:layout_height="@dimen/multi_user_avatar_expanded_size" + android:layout_gravity="center" + android:scaleType="centerInside" /> + </com.android.systemui.statusbar.phone.MultiUserSwitch> + + <com.android.systemui.statusbar.AlphaOptimizedFrameLayout + android:id="@+id/settings_button_container" + android:layout_width="0dp" + android:layout_height="@dimen/qs_footer_action_button_size" + android:layout_marginEnd="@dimen/qs_tile_margin_horizontal" + android:background="@drawable/qs_footer_action_chip_background" + android:layout_weight="1" + android:clipChildren="false" + android:clipToPadding="false"> + + <com.android.systemui.statusbar.phone.SettingsButton + android:id="@+id/settings_button" + android:layout_width="match_parent" + android:layout_height="@dimen/qs_footer_action_button_size" + android:layout_gravity="center" + android:contentDescription="@string/accessibility_quick_settings_settings" + android:background="@drawable/qs_footer_action_chip_background_borderless" + android:padding="@dimen/qs_footer_icon_padding" + android:scaleType="centerInside" + android:src="@drawable/ic_settings" + android:tint="?android:attr/colorForeground" /> + + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:id="@+id/tuner_icon" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingStart="36dp" + android:paddingEnd="4dp" + android:src="@drawable/tuner" + android:tint="?android:attr/textColorTertiary" + android:visibility="invisible" /> + + </com.android.systemui.statusbar.AlphaOptimizedFrameLayout> + + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:id="@+id/pm_lite" + android:layout_width="0dp" + android:layout_height="@dimen/qs_footer_action_button_size" + android:layout_weight="1" + android:background="@drawable/qs_footer_action_chip_background" + android:clickable="true" + android:clipToPadding="false" + android:focusable="true" + android:padding="@dimen/qs_footer_icon_padding" + android:src="@*android:drawable/ic_lock_power_off" + android:contentDescription="@string/accessibility_quick_settings_power_menu" + android:tint="?android:attr/colorForeground" /> + + </LinearLayout> + </LinearLayout> + +</com.android.systemui.qs.QSFooterView> diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml index 77f17439c487..d29cf872fd26 100644 --- a/packages/SystemUI/res/layout/qs_panel.xml +++ b/packages/SystemUI/res/layout/qs_panel.xml @@ -42,7 +42,10 @@ android:background="@android:color/transparent" android:focusable="true" android:accessibilityTraversalBefore="@android:id/edit"> - <include layout="@layout/qs_footer_impl" /> + <ViewStub + android:id="@+id/qs_footer_stub" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> <include layout="@layout/qs_media_divider" android:id="@+id/divider"/> </com.android.systemui.qs.QSPanel> diff --git a/packages/SystemUI/res/layout/udfps_animation_view_bp.xml b/packages/SystemUI/res/layout/udfps_bp_view.xml index 0cfbf2e61dd1..f1c55ef16cdc 100644 --- a/packages/SystemUI/res/layout/udfps_animation_view_bp.xml +++ b/packages/SystemUI/res/layout/udfps_bp_view.xml @@ -14,9 +14,9 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<com.android.systemui.biometrics.UdfpsAnimationViewBp +<com.android.systemui.biometrics.UdfpsBpView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/udfps_animation_view" android:layout_width="match_parent" android:layout_height="match_parent"> -</com.android.systemui.biometrics.UdfpsAnimationViewBp> +</com.android.systemui.biometrics.UdfpsBpView> diff --git a/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml b/packages/SystemUI/res/layout/udfps_enroll_view.xml index 9b5752d2de59..40353052ca85 100644 --- a/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml +++ b/packages/SystemUI/res/layout/udfps_enroll_view.xml @@ -14,13 +14,13 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<com.android.systemui.biometrics.UdfpsAnimationViewEnroll +<com.android.systemui.biometrics.UdfpsEnrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/udfps_animation_view" android:layout_width="match_parent" android:layout_height="match_parent"> - <!-- Enrollment progress bar--> + <!-- Enrollment progress bar --> <com.android.systemui.biometrics.UdfpsProgressBar android:id="@+id/progress_bar" android:layout_width="match_parent" @@ -31,4 +31,9 @@ android:layout_gravity="center" android:visibility="gone"/> -</com.android.systemui.biometrics.UdfpsAnimationViewEnroll> + <!-- Fingerprint --> + <ImageView + android:id="@+id/udfps_enroll_animation_fp_view" + android:layout_width="match_parent" + android:layout_height="match_parent"/> +</com.android.systemui.biometrics.UdfpsEnrollView> diff --git a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml b/packages/SystemUI/res/layout/udfps_fpm_other_view.xml index 644d1adac46b..6ecbb473d720 100644 --- a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml +++ b/packages/SystemUI/res/layout/udfps_fpm_other_view.xml @@ -14,9 +14,15 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<com.android.systemui.biometrics.UdfpsAnimationViewKeyguard +<com.android.systemui.biometrics.UdfpsFpmOtherView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/udfps_animation_view" android:layout_width="match_parent" android:layout_height="match_parent"> -</com.android.systemui.biometrics.UdfpsAnimationViewKeyguard> + + <!-- Fingerprint --> + <ImageView + android:id="@+id/udfps_fpm_other_fp_view" + android:layout_width="match_parent" + android:layout_height="match_parent"/> +</com.android.systemui.biometrics.UdfpsFpmOtherView> diff --git a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml b/packages/SystemUI/res/layout/udfps_keyguard_view.xml index f32faa0df867..0199ccb04be6 100644 --- a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml +++ b/packages/SystemUI/res/layout/udfps_keyguard_view.xml @@ -14,9 +14,17 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<com.android.systemui.biometrics.UdfpsAnimationViewFpmOther +<com.android.systemui.biometrics.UdfpsKeyguardView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/udfps_animation_view" android:layout_width="match_parent" android:layout_height="match_parent"> -</com.android.systemui.biometrics.UdfpsAnimationViewFpmOther> + + <!-- TODO: add background protection --> + + <!-- Fingerprint --> + <ImageView + android:id="@+id/udfps_keyguard_animation_fp_view" + android:layout_width="match_parent" + android:layout_height="match_parent"/> +</com.android.systemui.biometrics.UdfpsKeyguardView> diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml index e24c9e99a405..50b2f209d871 100644 --- a/packages/SystemUI/res/layout/udfps_view.xml +++ b/packages/SystemUI/res/layout/udfps_view.xml @@ -22,6 +22,11 @@ android:layout_height="match_parent" systemui:sensorTouchAreaCoefficient="0.5"> + <ViewStub + android:id="@+id/animation_view" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + <com.android.systemui.biometrics.UdfpsSurfaceView android:id="@+id/hbm_view" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index c36f7cd630a9..424172458b80 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -36,6 +36,7 @@ <color name="qs_user_detail_icon_muted">#FFFFFFFF</color> <!-- not so muted after all --> <color name="qs_tile_disabled_color">#9E9E9E</color> <!-- 38% black --> <color name="qs_customize_decoration">@color/GM2_grey_300</color> + <color name="qs_footer_action_border">#2E312C</color> <!-- The color of the background in the separated list of the Global Actions menu --> <color name="global_actions_separated_background">#F5F5F5</color> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index b75a0bc1525a..92d9ca9e94d8 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -107,7 +107,7 @@ <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" --> <string name="quick_settings_tiles_stock" translatable="false"> - wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness,cameratoggle,mictoggle,controls + wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness,cameratoggle,mictoggle,controls,alarm </string> <!-- The tiles to display in QuickSettings --> @@ -180,6 +180,9 @@ <!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations --> <integer name="doze_pickup_vibration_threshold">2000</integer> + <!-- Doze: quick pickup duration to stay in AOD until the next gesture is triggered --> + <integer name="doze_quick_pickup_aod_duration">5000</integer> + <!-- Type of a sensor that provides a low-power estimate of the desired display brightness, suitable to listen to while the device is asleep (e.g. during always-on display) --> @@ -577,6 +580,9 @@ <!-- Whether wallet view is shown in landscape / seascape orientations --> <bool name="global_actions_show_landscape_wallet_view">false</bool> + <!-- Package name of the preferred system app to perform eSOS action --> + <string name="config_preferredEmergencySosPackage" translatable="false"></string> + <!-- Whether to use the split 2-column notification shade --> <bool name="config_use_split_notification_shade">false</bool> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 392eb496031a..885cd254a1ea 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -167,15 +167,11 @@ and the notification won't use this much, but is measured with wrap_content --> <dimen name="notification_messaging_actions_min_height">196dp</dimen> - <!-- Height of a call notification. Note that this is an upper bound - and the notification won't use this much, but is measured with wrap_content --> - <dimen name="call_notification_full_height">172dp</dimen> - <!-- a threshold in dp per second that is considered fast scrolling --> <dimen name="scroll_fast_threshold">1500dp</dimen> <!-- Height of a the shelf with the notification icons --> - <dimen name="notification_shelf_height">32dp</dimen> + <dimen name="notification_shelf_height">48dp</dimen> <!-- Minimum height of a notification to be interactable --> <dimen name="notification_min_interaction_height">40dp</dimen> @@ -415,6 +411,9 @@ <!-- The size of each of the icon buttons in the QS footer --> <dimen name="qs_footer_action_button_size">@dimen/qs_footer_height</dimen> + <!-- (48dp - 44dp) / 2 --> + <dimen name="qs_footer_action_inset">2dp</dimen> + <!-- Margins on each side of QS Footer --> <dimen name="qs_footer_margin">2dp</dimen> diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml index e5518928c98c..8cd5757247e2 100644 --- a/packages/SystemUI/res/values/flags.xml +++ b/packages/SystemUI/res/values/flags.xml @@ -46,4 +46,6 @@ <bool name="flag_navigation_bar_overlay">false</bool> <bool name="flag_pm_lite">false</bool> + + <bool name="flag_alarm_tile">false</bool> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 783f80c2ee02..6207449d63e6 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2312,6 +2312,9 @@ <!-- accessibility label for button to edit quick settings [CHAR LIMIT=NONE] --> <string name="accessibility_quick_settings_edit">Edit order of settings.</string> + <!-- accessibility label for button to open power menu [CHAR LIMIT=NONE] --> + <string name="accessibility_quick_settings_power_menu">Power menu</string> + <!-- accessibility label for paging indicator in quick settings [CHAR LIMITi=NONE] --> <string name="accessibility_quick_settings_page">Page <xliff:g name="current_page" example="1">%1$d</xliff:g> of <xliff:g name="num_pages" example="2">%2$d</xliff:g></string> @@ -2808,44 +2811,44 @@ <!-- Text to display when copying the build number off QS [CHAR LIMIT=NONE]--> <string name="build_number_copy_toast">Build number copied to clipboard.</string> - <!-- Status for last interaction with exact time [CHAR LIMIT=120] --> - <string name="last_interaction_status" translatable="false">Last chatted <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string> - <!-- Status for last interaction when less than a certain time window [CHAR LIMIT=120] --> - <string name="last_interaction_status_less_than" translatable="false">Last chatted less than <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string> - <!-- Status for last interaction when over a certain time window [CHAR LIMIT=120] --> - <string name="last_interaction_status_over" translatable="false">Last chatted over <xliff:g id="duration" example="1 week">%1$s</xliff:g> ago</string> - <!-- Status for conversation without interaction data [CHAR LIMIT=120] --> - <string name="basic_status" translatable="false">Open conversation</string> - <!-- Status for conversation without interaction data [CHAR LIMIT=120] --> - <string name="select_conversation_text" translatable="false">Select one conversation to show in your widget:</string> - <!-- Timestamp for notification with exact time [CHAR LIMIT=120] --> - <string name="timestamp" translatable="false"><xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string> - <!-- Timestamp for notification when less than a certain time window [CHAR LIMIT=120] --> - <string name="less_than_timestamp" translatable="false">Less than <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string> - <!-- Timestamp for notification when over a certain time window [CHAR LIMIT=120] --> - <string name="over_timestamp" translatable="false">Over <xliff:g id="duration" example="1 week">%1$s</xliff:g> ago</string> - <!-- Status text for a birthday today [CHAR LIMIT=30] --> - <string name="birthday_status" translatable="false">Birthday</string> - <!-- Status text for an upcoming birthday [CHAR LIMIT=30] --> - <string name="upcoming_birthday_status" translatable="false">Birthday soon</string> - <!-- Status text for an anniversary [CHAR LIMIT=30] --> - <string name="anniversary_status" translatable="false">Anniversary</string> - <!-- Status text for sharing location [CHAR LIMIT=30] --> - <string name="location_status" translatable="false">Sharing location</string> - <!-- Status text for a new story posted [CHAR LIMIT=30] --> - <string name="new_story_status" translatable="false">New story</string> - <!-- Status text for watching a video [CHAR LIMIT=30] --> - <string name="video_status" translatable="false">Watching</string> - <!-- Status text for listening to audio [CHAR LIMIT=30] --> - <string name="audio_status" translatable="false">Listening</string> - <!-- Status text for playing a game [CHAR LIMIT=30] --> - <string name="game_status" translatable="false">Playing</string> - <!-- Empty user name before user has selected a friend [CHAR LIMIT=30] --> - <string name="empty_user_name" translatable="false">Your friend</string> - <!-- Empty status shown before user has selected a friend [CHAR LIMIT=30] --> - <string name="empty_status" translatable="false">Their status</string> - <!-- Default text for missed call notifications [CHAR LIMIT=30] --> - <string name="missed_call" translatable="false">Missed call</string> + <!-- Status for conversation without interaction data [CHAR LIMIT=120] --> + <string name="basic_status">Open conversation</string> + <!--Title text for Conversation widget set up screen [CHAR LIMIT=180] --> + <string name="select_conversation_title">Conversation widgets</string> + <!--Text explaining to tap a conversation to select it show in their Conversation widget [CHAR LIMIT=180] --> + <string name="select_conversation_text">Tap a conversation to add it to your Home screen</string> + <!-- Timestamp for notification with exact time [CHAR LIMIT=25] --> + <string name="timestamp"><xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string> + <!-- Timestamp for notification when less than a certain time window [CHAR LIMIT=25] --> + <string name="less_than_timestamp">Less than <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string> + <!-- Timestamp for notification when over a certain time window [CHAR LIMIT=25] --> + <string name="over_timestamp">Over <xliff:g id="duration" example="1 week">%1$s</xliff:g> ago</string> + <!-- Status text on the Conversation widget for a birthday today [CHAR LIMIT=20] --> + <string name="birthday_status">Birthday</string> + <!-- Status text on the Conversation widget for an upcoming birthday [CHAR LIMIT=20] --> + <string name="upcoming_birthday_status">Birthday soon</string> + <!-- Status text on the Conversation widget for an anniversary [CHAR LIMIT=20] --> + <string name="anniversary_status">Anniversary</string> + <!-- Status text on the Conversation widget for sharing location [CHAR LIMIT=20] --> + <string name="location_status">Sharing location</string> + <!-- Status text on the Conversation widget for a new story posted [CHAR LIMIT=20] --> + <string name="new_story_status">New story</string> + <!-- Status text on the Conversation widget for watching a video [CHAR LIMIT=20] --> + <string name="video_status">Watching</string> + <!-- Status text on the Conversation widget for listening to audio [CHAR LIMIT=20] --> + <string name="audio_status">Listening</string> + <!-- Status text on the Conversation widget for playing a game [CHAR LIMIT=20] --> + <string name="game_status">Playing</string> + <!-- Empty user name before user has selected a friend for their Conversation widget [CHAR LIMIT=20] --> + <string name="empty_user_name">Friends</string> + <!-- Empty status shown before user has selected a friend for their Conversation widget [CHAR LIMIT=20] --> + <string name="empty_status">Let’s chat tonight!</string> + <!-- Default text for missed call notifications on their Conversation widget [CHAR LIMIT=20] --> + <string name="missed_call">Missed call</string> + <!-- Description text for adding a Conversation widget [CHAR LIMIT=100] --> + <string name="people_tile_description">See recent messages, missed calls, and status updates</string> + <!-- Title text displayed for the Conversation widget [CHAR LIMIT=50] --> + <string name="people_tile_title">Conversation</string> <!-- Title to display in a notification when ACTION_BATTERY_CHANGED.EXTRA_PRESENT field is false [CHAR LIMIT=NONE] --> @@ -2858,4 +2861,7 @@ <string name="qs_remove_labels" translatable="false"></string> <string name="qs_tile_label_fontFamily" translatable="false">@*android:string/config_headlineFontFamily</string> + + <!-- Secondary label for alarm tile when there is no next alarm information [CHAR LIMIT=20] --> + <string name="qs_alarm_tile_no_alarm">No alarm set</string> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index ec26b8d7a6a8..fb885cb3fdbe 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -244,6 +244,8 @@ <item name="android:paddingTop">12dp</item> <item name="android:paddingHorizontal">24dp</item> <item name="android:textSize">24sp</item> + <item name="android:singleLine">true</item> + <item name="android:ellipsize">marquee</item> </style> <style name="TextAppearance.AuthCredential.Subtitle"> @@ -251,6 +253,8 @@ <item name="android:paddingTop">8dp</item> <item name="android:paddingHorizontal">24dp</item> <item name="android:textSize">16sp</item> + <item name="android:singleLine">true</item> + <item name="android:ellipsize">marquee</item> </style> <style name="TextAppearance.AuthCredential.Description"> @@ -258,6 +262,8 @@ <item name="android:paddingTop">8dp</item> <item name="android:paddingHorizontal">24dp</item> <item name="android:textSize">14sp</item> + <item name="android:singleLine">true</item> + <item name="android:ellipsize">marquee</item> </style> <style name="TextAppearance.AuthCredential.Error"> @@ -643,6 +649,16 @@ <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item> </style> + <style name="Theme.ControlsActivity" parent="@android:style/Theme.DeviceDefault.NoActionBar"> + <item name="android:windowActivityTransitions">true</item> + <item name="android:windowContentTransitions">false</item> + <item name="android:windowIsTranslucent">false</item> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowAnimationStyle">@null</item> + <item name="android:statusBarColor">@*android:color/transparent</item> + <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item> + </style> + <style name="Theme.CreateUser" parent="@style/Theme.SystemUI"> <item name="android:windowIsTranslucent">true</item> <item name="android:windowBackground">#33000000</item> @@ -654,30 +670,12 @@ <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> </style> - <style name="Theme.SystemUI.Dialog.Control.DetailPanel" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar"> - <item name="android:windowAnimationStyle">@style/Animation.Bottomsheet</item> - <item name="android:windowFullscreen">true</item> + <style name="Theme.SystemUI.Dialog.Control.DetailPanel" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar"> + <item name="android:windowFullscreen">false</item> <item name="android:windowIsFloating">false</item> - <item name="android:windowBackground">@null</item> - <item name="android:backgroundDimEnabled">true</item> - </style> - - <style name="Animation.Bottomsheet"> - <item name="android:windowEnterAnimation">@anim/bottomsheet_in</item> - <item name="android:windowExitAnimation">@anim/bottomsheet_out</item> - </style> - - <style name="Theme.SystemUI.Dialog.Control.LockScreen" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar"> - <item name="android:windowAnimationStyle">@style/Animation.ControlDialog</item> - <item name="android:windowFullscreen">true</item> - <item name="android:windowIsFloating">false</item> - <item name="android:windowBackground">@null</item> - <item name="android:backgroundDimEnabled">true</item> - </style> - - <style name="Animation.ControlDialog"> - <item name="android:windowEnterAnimation">@*android:anim/dialog_enter</item> - <item name="android:windowExitAnimation">@*android:anim/dialog_exit</item> + <item name="android:windowBackground">@android:color/black</item> + <item name="android:backgroundDimEnabled">false</item> + <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item> </style> <style name="Control" /> diff --git a/packages/SystemUI/res/xml/people_space_widget_info.xml b/packages/SystemUI/res/xml/people_space_widget_info.xml index fbdac5e1789b..35188d8e11ad 100644 --- a/packages/SystemUI/res/xml/people_space_widget_info.xml +++ b/packages/SystemUI/res/xml/people_space_widget_info.xml @@ -20,8 +20,9 @@ android:minResizeWidth="110dp" android:minResizeHeight="55dp" android:updatePeriodMillis="60000" - android:previewImage="@drawable/ic_person" + android:description="@string/people_tile_description" + android:previewLayout="@layout/people_space_placeholder_layout" android:resizeMode="horizontal|vertical" android:configure="com.android.systemui.people.PeopleSpaceActivity" - android:initialLayout="@layout/people_space_widget"> + android:initialLayout="@layout/people_space_placeholder_layout"> </appwidget-provider> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java index ebb6e30d4b3b..e9e9b2421d4a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java @@ -289,15 +289,19 @@ public class Task { /** * Returns the visible width to height ratio. Returns 0f if snapshot data is not available. */ - public float getVisibleThumbnailRatio() { + public float getVisibleThumbnailRatio(boolean clipInsets) { if (lastSnapshotData.taskSize == null || lastSnapshotData.contentInsets == null) { return 0f; } - float availableWidth = lastSnapshotData.taskSize.x - (lastSnapshotData.contentInsets.left - + lastSnapshotData.contentInsets.right); - float availableHeight = lastSnapshotData.taskSize.y - (lastSnapshotData.contentInsets.top - + lastSnapshotData.contentInsets.bottom); + float availableWidth = lastSnapshotData.taskSize.x; + float availableHeight = lastSnapshotData.taskSize.y; + if (clipInsets) { + availableWidth -= + (lastSnapshotData.contentInsets.left + lastSnapshotData.contentInsets.right); + availableHeight -= + (lastSnapshotData.contentInsets.top + lastSnapshotData.contentInsets.bottom); + } return availableWidth / availableHeight; } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java index af7c5da7b878..c2d52a7855f4 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -16,11 +16,11 @@ package com.android.systemui.shared.system; -import android.window.TaskSnapshot; import android.graphics.Rect; import android.os.RemoteException; import android.util.Log; import android.view.IRecentsAnimationController; +import android.window.TaskSnapshot; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -141,9 +141,9 @@ public class RecentsAnimationControllerCompat { /** * @see IRecentsAnimationController#detachNavigationBarFromApp */ - public void detachNavigationBarFromApp() { + public void detachNavigationBarFromApp(boolean moveHomeToTop) { try { - mAnimationController.detachNavigationBarFromApp(); + mAnimationController.detachNavigationBarFromApp(moveHomeToTop); } catch (RemoteException e) { Log.e(TAG, "Failed to detach the navigation bar from app", e); } diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java index 1569fff63453..3f0e3eb84424 100644 --- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java @@ -45,6 +45,7 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie private int mLockScreenColor; private boolean mIsDozing; + private float mDozeAmount; private Locale mLocale; private final NumberFormat mBurmeseNf = NumberFormat.getInstance(Locale.forLanguageTag("my")); @@ -59,6 +60,7 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie super(view); mStatusBarStateController = statusBarStateController; mIsDozing = mStatusBarStateController.isDozing(); + mDozeAmount = mStatusBarStateController.getDozeAmount(); mBroadcastDispatcher = broadcastDispatcher; mBurmeseNumerals = mBurmeseNf.format(FORMAT_NUMBER); @@ -82,6 +84,7 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie new IntentFilter(Intent.ACTION_LOCALE_CHANGED)); mStatusBarStateController.addCallback(mStatusBarStateListener); mIsDozing = mStatusBarStateController.isDozing(); + mDozeAmount = mStatusBarStateController.getDozeAmount(); refreshTime(); initColors(); } @@ -136,9 +139,15 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie private final StatusBarStateController.StateListener mStatusBarStateListener = new StatusBarStateController.StateListener() { @Override - public void onDozingChanged(boolean isDozing) { - mIsDozing = isDozing; - mView.animateDoze(mIsDozing, true); + public void onDozeAmountChanged(float linear, float eased) { + boolean noAnimation = (mDozeAmount == 0f && linear == 1f) + || (mDozeAmount == 1f && linear == 0f); + boolean isDozing = linear > mDozeAmount; + mDozeAmount = linear; + if (mIsDozing != isDozing) { + mIsDozing = isDozing; + mView.animateDoze(mIsDozing, !noAnimation); + } } }; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index 5760565aaab1..a580663cfa91 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -35,12 +35,15 @@ import com.android.keyguard.EmergencyButton.EmergencyButtonCallback; import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.R; +import com.android.systemui.classifier.FalsingClassifier; +import com.android.systemui.classifier.FalsingCollector; public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKeyInputView> extends KeyguardInputViewController<T> { private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final LockPatternUtils mLockPatternUtils; private final LatencyTracker mLatencyTracker; + private final FalsingCollector mFalsingCollector; private CountDownTimer mCountdownTimer; protected KeyguardMessageAreaController mMessageAreaController; private boolean mDismissing; @@ -70,11 +73,12 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey LockPatternUtils lockPatternUtils, KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, - LatencyTracker latencyTracker) { + LatencyTracker latencyTracker, FalsingCollector falsingCollector) { super(view, securityMode, keyguardSecurityCallback); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; + mFalsingCollector = falsingCollector; KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView); mMessageAreaController = messageAreaControllerFactory.create(kma); } @@ -256,6 +260,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey } protected void onUserInput() { + mFalsingCollector.updateFalseConfidence(FalsingClassifier.Result.passed(0.6)); getKeyguardSecurityCallback().userActivity(); getKeyguardSecurityCallback().onUserInput(); mMessageAreaController.setMessage(""); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java index 5e02e0440c3d..de64f07259b4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java @@ -26,16 +26,11 @@ import android.widget.LinearLayout; import androidx.annotation.Nullable; import com.android.internal.jank.InteractionJankMonitor; -import com.android.systemui.Gefingerpoken; - -import java.util.ArrayList; -import java.util.List; /** * A Base class for all Keyguard password/pattern/pin related inputs. */ public abstract class KeyguardInputView extends LinearLayout { - private final List<Gefingerpoken> mMotionEventListener = new ArrayList<>(); public KeyguardInputView(Context context) { super(context); @@ -53,7 +48,6 @@ public abstract class KeyguardInputView extends LinearLayout { abstract CharSequence getTitle(); void animateForIme(float interpolatedFraction) { - return; } boolean disallowInterceptTouch(MotionEvent event) { @@ -66,27 +60,6 @@ public abstract class KeyguardInputView extends LinearLayout { return false; } - void addMotionEventListener(Gefingerpoken listener) { - mMotionEventListener.add(listener); - } - - void removeMotionEventListener(Gefingerpoken listener) { - mMotionEventListener.remove(listener); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - return mMotionEventListener.stream().anyMatch(listener -> listener.onTouchEvent(event)) - || super.onTouchEvent(event); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent event) { - return mMotionEventListener.stream().anyMatch( - listener -> listener.onInterceptTouchEvent(event)) - || super.onInterceptTouchEvent(event); - } - protected AnimatorListenerAdapter getAnimationListener(int cuj) { return new AnimatorListenerAdapter() { private boolean mIsCancel; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index 957882dc9c6b..05f33a9d0997 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -155,8 +155,8 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> private final InputMethodManager mInputMethodManager; private final DelayableExecutor mMainExecutor; private final Resources mResources; - private LiftToActivateListener mLiftToActivateListener; - private TelephonyManager mTelephonyManager; + private final LiftToActivateListener mLiftToActivateListener; + private final TelephonyManager mTelephonyManager; private final FalsingCollector mFalsingCollector; private final boolean mIsNewLayoutEnabled; @@ -167,8 +167,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> KeyguardMessageAreaController.Factory messageAreaControllerFactory, InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor, @Main Resources resources, LiftToActivateListener liftToActivateListener, - TelephonyManager telephonyManager, - FalsingCollector falsingCollector, + TelephonyManager telephonyManager, FalsingCollector falsingCollector, FeatureFlags featureFlags) { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; @@ -189,12 +188,13 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> if (keyguardInputView instanceof KeyguardPatternView) { return new KeyguardPatternViewController((KeyguardPatternView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, - keyguardSecurityCallback, mLatencyTracker, mMessageAreaControllerFactory); + keyguardSecurityCallback, mLatencyTracker, mFalsingCollector, + mMessageAreaControllerFactory); } else if (keyguardInputView instanceof KeyguardPasswordView) { return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mInputMethodManager, mMainExecutor, mResources); + mInputMethodManager, mMainExecutor, mResources, mFalsingCollector); } else if (keyguardInputView instanceof KeyguardPINView) { return new KeyguardPinViewController((KeyguardPINView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, @@ -204,14 +204,14 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mLiftToActivateListener, mTelephonyManager, - mFalsingCollector, mIsNewLayoutEnabled); + mLiftToActivateListener, mTelephonyManager, mFalsingCollector, + mIsNewLayoutEnabled); } else if (keyguardInputView instanceof KeyguardSimPukView) { return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mLiftToActivateListener, mTelephonyManager, - mFalsingCollector, mIsNewLayoutEnabled); + mLiftToActivateListener, mTelephonyManager, mFalsingCollector, + mIsNewLayoutEnabled); } throw new RuntimeException("Unable to find controller for " + keyguardInputView); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java index 0f1c3c8a20b7..57b8cf09556e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -40,6 +40,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.settingslib.Utils; import com.android.systemui.R; +import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -112,9 +113,10 @@ public class KeyguardPasswordViewController LatencyTracker latencyTracker, InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor, - @Main Resources resources) { + @Main Resources resources, + FalsingCollector falsingCollector) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, - messageAreaControllerFactory, latencyTracker); + messageAreaControllerFactory, latencyTracker, falsingCollector); mKeyguardSecurityCallback = keyguardSecurityCallback; mInputMethodManager = inputMethodManager; mMainExecutor = mainExecutor; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index 2aaf748e2415..4f48bb4f3260 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -23,6 +23,7 @@ import android.content.res.ColorStateList; import android.os.AsyncTask; import android.os.CountDownTimer; import android.os.SystemClock; +import android.view.MotionEvent; import android.view.View; import com.android.internal.util.LatencyTracker; @@ -35,6 +36,8 @@ import com.android.keyguard.EmergencyButton.EmergencyButtonCallback; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.settingslib.Utils; import com.android.systemui.R; +import com.android.systemui.classifier.FalsingClassifier; +import com.android.systemui.classifier.FalsingCollector; import java.util.List; @@ -50,6 +53,7 @@ public class KeyguardPatternViewController private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final LockPatternUtils mLockPatternUtils; private final LatencyTracker mLatencyTracker; + private final FalsingCollector mFalsingCollector; private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory; private KeyguardMessageAreaController mMessageAreaController; @@ -102,6 +106,11 @@ public class KeyguardPatternViewController final int userId = KeyguardUpdateMonitor.getCurrentUser(); if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { + // Treat single-sized patterns as erroneous taps. + if (pattern.size() == 1) { + mFalsingCollector.updateFalseConfidence(FalsingClassifier.Result.falsed( + 0.7, "empty pattern input")); + } mLockPatternView.enableInput(); onPatternChecked(userId, false, 0, false /* not valid - too short */); return; @@ -179,11 +188,13 @@ public class KeyguardPatternViewController LockPatternUtils lockPatternUtils, KeyguardSecurityCallback keyguardSecurityCallback, LatencyTracker latencyTracker, + FalsingCollector falsingCollector, KeyguardMessageAreaController.Factory messageAreaControllerFactory) { super(view, securityMode, keyguardSecurityCallback); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; + mFalsingCollector = falsingCollector; mMessageAreaControllerFactory = messageAreaControllerFactory; KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView); mMessageAreaController = mMessageAreaControllerFactory.create(kma); @@ -205,6 +216,12 @@ public class KeyguardPatternViewController KeyguardUpdateMonitor.getCurrentUser())); // vibrate mode will be the same for the life of this screen mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); + mLockPatternView.setOnTouchListener((v, event) -> { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + mFalsingCollector.avoidGesture(); + } + return false; + }); EmergencyButton button = mView.findViewById(R.id.emergency_call_button); if (button != null) { @@ -224,6 +241,7 @@ public class KeyguardPatternViewController protected void onViewDetached() { super.onViewDetached(); mLockPatternView.setOnPatternListener(null); + mLockPatternView.setOnTouchListener(null); EmergencyButton button = mView.findViewById(R.id.emergency_call_button); if (button != null) { button.setCallback(null); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index 4e06491621cb..09fb8efba4e8 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -164,6 +164,10 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView reloadColors(); } + NumPadKey[] getButtons() { + return mButtons; + } + /** * By default, the new layout will be enabled. When false, revert to the old style. */ diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java index f2479488db0f..b156f8169b50 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java @@ -25,7 +25,6 @@ import android.view.View.OnTouchListener; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; -import com.android.systemui.Gefingerpoken; import com.android.systemui.R; import com.android.systemui.classifier.FalsingCollector; @@ -50,19 +49,6 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB return false; }; - private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() { - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - mFalsingCollector.avoidGesture(); - return false; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - return false; - } - }; - protected KeyguardPinBasedInputViewController(T view, KeyguardUpdateMonitor keyguardUpdateMonitor, SecurityMode securityMode, @@ -73,7 +59,7 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB LiftToActivateListener liftToActivateListener, FalsingCollector falsingCollector) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, - messageAreaControllerFactory, latencyTracker); + messageAreaControllerFactory, latencyTracker, falsingCollector); mLiftToActivateListener = liftToActivateListener; mFalsingCollector = falsingCollector; mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId()); @@ -83,8 +69,14 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB protected void onViewAttached() { super.onViewAttached(); - mView.addMotionEventListener(mGlobalTouchListener); - + for (NumPadKey button: mView.getButtons()) { + button.setOnTouchListener((v, event) -> { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + mFalsingCollector.avoidGesture(); + } + return false; + }); + } mPasswordEntry.setOnKeyListener(mOnKeyListener); mPasswordEntry.setUserActivityListener(this::onUserInput); @@ -123,7 +115,10 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB @Override protected void onViewDetached() { super.onViewDetached(); - mView.removeMotionEventListener(mGlobalTouchListener); + + for (NumPadKey button: mView.getButtons()) { + button.setOnTouchListener(null); + } } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index a2d7707a1569..eaf8516ac152 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -58,10 +58,12 @@ import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.Gefingerpoken; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import java.util.ArrayList; import java.util.List; public class KeyguardSecurityContainer extends FrameLayout { @@ -97,6 +99,7 @@ public class KeyguardSecurityContainer extends FrameLayout { private final ViewConfiguration mViewConfiguration; private final SpringAnimation mSpringAnimation; private final VelocityTracker mVelocityTracker = VelocityTracker.obtain(); + private final List<Gefingerpoken> mMotionEventListeners = new ArrayList<>(); private float mLastTouchY = -1; private int mActivePointerId = -1; @@ -388,6 +391,10 @@ public class KeyguardSecurityContainer extends FrameLayout { @Override public boolean onInterceptTouchEvent(MotionEvent event) { + boolean result = mMotionEventListeners.stream().anyMatch( + listener -> listener.onInterceptTouchEvent(event)) + || super.onInterceptTouchEvent(event); + switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: int pointerIndex = event.getActionIndex(); @@ -418,12 +425,17 @@ public class KeyguardSecurityContainer extends FrameLayout { mIsDragging = false; break; } - return false; + return result; } @Override public boolean onTouchEvent(MotionEvent event) { final int action = event.getActionMasked(); + + boolean result = mMotionEventListeners.stream() + .anyMatch(listener -> listener.onTouchEvent(event)) + || super.onTouchEvent(event); + switch (action) { case MotionEvent.ACTION_MOVE: mVelocityTracker.addMovement(event); @@ -469,6 +481,14 @@ public class KeyguardSecurityContainer extends FrameLayout { return true; } + void addMotionEventListener(Gefingerpoken listener) { + mMotionEventListeners.add(listener); + } + + void removeMotionEventListener(Gefingerpoken listener) { + mMotionEventListeners.remove(listener); + } + private void handleTap(MotionEvent event) { // If we're using a fullscreen security mode, skip if (!mOneHandedMode) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index fdab8db67431..7eac9034f02a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -33,6 +33,7 @@ import android.metrics.LogMaker; import android.os.UserHandle; import android.util.Log; import android.util.Slog; +import android.view.MotionEvent; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; @@ -46,6 +47,8 @@ import com.android.keyguard.KeyguardSecurityContainer.SwipeListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.settingslib.utils.ThreadUtils; +import com.android.systemui.Gefingerpoken; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -71,9 +74,44 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController; private final SecurityCallback mSecurityCallback; private final ConfigurationController mConfigurationController; + private final KeyguardViewController mKeyguardViewController; + private final FalsingManager mFalsingManager; private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid; + private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() { + private MotionEvent mTouchDown; + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + // Do just a bit of our own falsing. People should only be tapping on the input, not + // swiping. + if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { + if (mTouchDown != null) { + mTouchDown.recycle(); + mTouchDown = null; + } + mTouchDown = MotionEvent.obtain(ev); + } else if (mTouchDown != null) { + boolean tapResult = mFalsingManager.isFalseTap(true, 0.6); + if (tapResult + || ev.getActionMasked() == MotionEvent.ACTION_UP + || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) { + if (tapResult) { + mKeyguardViewController.reset(true); + } + mTouchDown.recycle(); + mTouchDown = null; + } + } + return false; + } + }; + private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() { public void userActivity() { if (mSecurityCallback != null) { @@ -169,7 +207,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard KeyguardStateController keyguardStateController, SecurityCallback securityCallback, KeyguardSecurityViewFlipperController securityViewFlipperController, - ConfigurationController configurationController) { + ConfigurationController configurationController, + KeyguardViewController keyguardViewController, + FalsingManager falsingManager) { super(view); mLockPatternUtils = lockPatternUtils; mUpdateMonitor = keyguardUpdateMonitor; @@ -182,6 +222,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create( mKeyguardSecurityCallback); mConfigurationController = configurationController; + mKeyguardViewController = keyguardViewController; + mFalsingManager = falsingManager; } @Override @@ -192,12 +234,14 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard @Override protected void onViewAttached() { mView.setSwipeListener(mSwipeListener); + mView.addMotionEventListener(mGlobalTouchListener); mConfigurationController.addCallback(mConfigurationListener); } @Override protected void onViewDetached() { mConfigurationController.removeCallback(mConfigurationListener); + mView.removeMotionEventListener(mGlobalTouchListener); } /** */ @@ -479,6 +523,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final KeyguardStateController mKeyguardStateController; private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController; private final ConfigurationController mConfigurationController; + private final KeyguardViewController mKeyguardViewController; + private final FalsingManager mFalsingManager; @Inject Factory(KeyguardSecurityContainer view, @@ -491,7 +537,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard UiEventLogger uiEventLogger, KeyguardStateController keyguardStateController, KeyguardSecurityViewFlipperController securityViewFlipperController, - ConfigurationController configurationController) { + ConfigurationController configurationController, + KeyguardViewController keyguardViewController, + FalsingManager falsingManager) { mView = view; mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory; mLockPatternUtils = lockPatternUtils; @@ -502,6 +550,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mKeyguardStateController = keyguardStateController; mSecurityViewFlipperController = securityViewFlipperController; mConfigurationController = configurationController; + mKeyguardViewController = keyguardViewController; + mFalsingManager = falsingManager; } public KeyguardSecurityContainerController create( @@ -510,7 +560,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger, mKeyguardStateController, securityCallback, mSecurityViewFlipperController, - mConfigurationController); + mConfigurationController, mKeyguardViewController, mFalsingManager); } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java index cdbbfe643812..b2bf2e674b33 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java @@ -78,8 +78,8 @@ public class KeyguardSimPinViewController KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, - TelephonyManager telephonyManager, - FalsingCollector falsingCollector, boolean isNewLayoutEnabled) { + TelephonyManager telephonyManager, FalsingCollector falsingCollector, + boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, falsingCollector); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java index 8fff34278216..620db481e4a2 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java @@ -85,8 +85,8 @@ public class KeyguardSimPukViewController KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, - TelephonyManager telephonyManager, - FalsingCollector falsingCollector, boolean isNewLayoutEnabled) { + TelephonyManager telephonyManager, FalsingCollector falsingCollector, + boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, falsingCollector); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index a4054bea1167..69e6ed043172 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2077,8 +2077,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab boolean shouldListenForUdfps() { return shouldListenForFingerprint() && !mBouncer - && mStatusBarState != StatusBarState.SHADE_LOCKED - && mStatusBarState != StatusBarState.FULLSCREEN_USER_SWITCHER && mStrongAuthTracker.hasUserAuthenticatedSinceBoot(); } diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 3852b24fe4b3..fba34e0b8ad3 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -367,7 +367,7 @@ public class SwipeHelper implements Gefingerpoken { } /** - * @param view The view to be dismissed + * @param animView The view to be dismissed * @param velocity The desired pixels/second speed at which the view should move * @param endAction The action to perform at the end * @param delay The delay after which we should start @@ -477,12 +477,8 @@ public class SwipeHelper implements Gefingerpoken { public void snapChild(final View animView, final float targetLeft, float velocity) { final boolean canBeDismissed = mCallback.canChildBeDismissed(animView); - AnimatorUpdateListener updateListener = new AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed); - } - }; + AnimatorUpdateListener updateListener = animation -> onTranslationUpdate(animView, + (float) animation.getAnimatedValue(), canBeDismissed); Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener); if (anim == null) { @@ -501,8 +497,6 @@ public class SwipeHelper implements Gefingerpoken { mSnappingChild = false; if (!wasCancelled) { updateSwipeProgressFromOffset(animView, canBeDismissed); - onChildSnappedBack(animView, targetLeft); - mCallback.onChildSnappedBack(animView, targetLeft); resetSwipeState(); } } @@ -513,6 +507,7 @@ public class SwipeHelper implements Gefingerpoken { mFlingAnimationUtils.apply(anim, getTranslation(animView), targetLeft, velocity, maxDistance); anim.start(); + mCallback.onChildSnappedBack(animView, targetLeft); } /** @@ -594,13 +589,12 @@ public class SwipeHelper implements Gefingerpoken { if (!mIsSwiping && !mMenuRowIntercepting) { if (mCallback.getChildAtPosition(ev) != null) { - // We are dragging directly over a card, make sure that we also catch the gesture // even if nobody else wants the touch event. + mTouchedView = mCallback.getChildAtPosition(ev); onInterceptTouchEvent(ev); return true; } else { - // We are not doing anything, make sure the long press callback // is not still ticking like a bomb waiting to go off. cancelLongPress(); diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index e85cafaf47ac..d3168c8d2a05 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -170,7 +170,9 @@ public class AssistManager { boolean visible = false; if (mView != null) { visible = mView.isShowing(); - mWindowManager.removeView(mView); + if (mView.isAttachedToWindow()) { + mWindowManager.removeView(mView); + } } mView = (AssistOrbContainer) LayoutInflater.from(mContext).inflate( diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java index cc608ef87bc6..007080bc8603 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java @@ -16,17 +16,22 @@ package com.android.systemui.biometrics; +import android.annotation.IdRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.graphics.Insets; import android.graphics.Rect; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.util.AttributeSet; import android.util.Log; +import android.view.Surface; import android.view.View; import android.view.WindowInsets; import android.view.WindowManager; +import android.widget.FrameLayout; +import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; /** @@ -51,53 +56,38 @@ public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView { mSensorProps = prop; } - /** - * For devices where the sensor is too high up, calculates the amount of padding necessary to - * move/center the biometric icon within the sensor's physical location. - */ - static int calculateBottomSpacerHeight(int displayHeightPx, int navbarHeightPx, - int dialogBottomMarginPx, @NonNull View buttonBar, @NonNull View textIndicator, - @NonNull FingerprintSensorPropertiesInternal sensorProperties) { - final int sensorDistanceFromBottom = displayHeightPx - sensorProperties.sensorLocationY - - sensorProperties.sensorRadius; - - final int spacerHeight = sensorDistanceFromBottom - - textIndicator.getMeasuredHeight() - - buttonBar.getMeasuredHeight() - - dialogBottomMarginPx - - navbarHeightPx; - - Log.d(TAG, "Display height: " + displayHeightPx - + ", Distance from bottom: " + sensorDistanceFromBottom - + ", Bottom margin: " + dialogBottomMarginPx - + ", Navbar height: " + navbarHeightPx - + ", Spacer height: " + spacerHeight); - - return spacerHeight; - } - @Override + @NonNull AuthDialog.LayoutParams onMeasureInternal(int width, int height) { - final View spaceBelowIcon = findViewById(R.id.space_below_icon); - spaceBelowIcon.setVisibility(View.VISIBLE); + final int displayRotation = getDisplay().getRotation(); + switch (displayRotation) { + case Surface.ROTATION_0: + return onMeasureInternalPortrait(width, height); + case Surface.ROTATION_90: + case Surface.ROTATION_270: + return onMeasureInternalLandscape(width, height); + default: + Log.e(TAG, "Unsupported display rotation: " + displayRotation); + return super.onMeasureInternal(width, height); + } + } + @NonNull + private AuthDialog.LayoutParams onMeasureInternalPortrait(int width, int height) { // Get the height of the everything below the icon. Currently, that's the indicator and - // button bar - final View textIndicator = findViewById(R.id.indicator); - final View buttonBar = findViewById(R.id.button_bar); + // button bar. + final int textIndicatorHeight = getViewHeightPx(R.id.indicator); + final int buttonBarHeight = getViewHeightPx(R.id.button_bar); // Figure out where the bottom of the sensor anim should be. // Navbar + dialogMargin + buttonBar + textIndicator + spacerHeight = sensorDistFromBottom - final int dialogBottomMarginPx = getResources() - .getDimensionPixelSize(R.dimen.biometric_dialog_border_padding); - final WindowManager wm = getContext().getSystemService(WindowManager.class); - final Rect bounds = wm.getCurrentWindowMetrics().getBounds(); - final int navbarHeight = wm.getCurrentWindowMetrics().getWindowInsets() - .getInsets(WindowInsets.Type.navigationBars()).toRect().height(); - final int displayHeight = bounds.height(); - - final int spacerHeight = calculateBottomSpacerHeight(displayHeight, navbarHeight, - dialogBottomMarginPx, buttonBar, textIndicator, mSensorProps); + final int dialogMargin = getDialogMarginPx(); + final WindowManager windowManager = getContext().getSystemService(WindowManager.class); + final int displayHeight = getWindowBounds(windowManager).height(); + final Insets navbarInsets = getNavbarInsets(windowManager); + final int bottomSpacerHeight = calculateBottomSpacerHeightForPortrait( + mSensorProps, displayHeight, textIndicatorHeight, buttonBarHeight, + dialogMargin, navbarInsets.bottom); // Go through each of the children and do the custom measurement. int totalHeight = 0; @@ -105,22 +95,25 @@ public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView { final int sensorDiameter = mSensorProps.sensorRadius * 2; for (int i = 0; i < numChildren; i++) { final View child = getChildAt(i); - if (child.getId() == R.id.biometric_icon_frame) { - // Create a frame that's exactly the size of the sensor circle - child.measure( - MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY)); - } else if (child.getId() == R.id.biometric_icon) { - // Icon should never be larger than the circle - child.measure( + final FrameLayout iconFrame = (FrameLayout) child; + final View icon = iconFrame.getChildAt(0); + + // Ensure that the icon is never larger than the sensor. + icon.measure( MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST)); + + // Create a frame that's exactly the height of the sensor circle. + iconFrame.measure( + MeasureSpec.makeMeasureSpec( + child.getLayoutParams().width, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY)); } else if (child.getId() == R.id.space_above_icon) { child.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(child.getLayoutParams().height, - MeasureSpec.EXACTLY)); + MeasureSpec.makeMeasureSpec( + child.getLayoutParams().height, MeasureSpec.EXACTLY)); } else if (child.getId() == R.id.button_bar) { child.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), @@ -128,8 +121,9 @@ public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView { MeasureSpec.EXACTLY)); } else if (child.getId() == R.id.space_below_icon) { // Set the spacer height so the fingerprint icon is on the physical sensor area - child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(spacerHeight, MeasureSpec.EXACTLY)); + child.measure( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(bottomSpacerHeight, MeasureSpec.EXACTLY)); } else { child.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), @@ -143,4 +137,184 @@ public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView { return new AuthDialog.LayoutParams(width, totalHeight); } + + @NonNull + private AuthDialog.LayoutParams onMeasureInternalLandscape(int width, int height) { + // Find the spacer height needed to vertically align the icon with the sensor. + final int titleHeight = getViewHeightPx(R.id.title); + final int subtitleHeight = getViewHeightPx(R.id.subtitle); + final int descriptionHeight = getViewHeightPx(R.id.description); + final int topSpacerHeight = getViewHeightPx(R.id.space_above_icon); + final int textIndicatorHeight = getViewHeightPx(R.id.indicator); + final int buttonBarHeight = getViewHeightPx(R.id.button_bar); + final WindowManager windowManager = getContext().getSystemService(WindowManager.class); + final Insets navbarInsets = getNavbarInsets(windowManager); + final int bottomSpacerHeight = calculateBottomSpacerHeightForLandscape(titleHeight, + subtitleHeight, descriptionHeight, topSpacerHeight, textIndicatorHeight, + buttonBarHeight, navbarInsets.bottom); + + // Find the spacer width needed to horizontally align the icon with the sensor. + final int displayWidth = getWindowBounds(windowManager).width(); + final int dialogMargin = getDialogMarginPx(); + final int horizontalInset = navbarInsets.left + navbarInsets.right; + final int horizontalSpacerWidth = calculateHorizontalSpacerWidthForLandscape( + mSensorProps, displayWidth, dialogMargin, horizontalInset); + + final int sensorDiameter = mSensorProps.sensorRadius * 2; + final int remeasuredWidth = sensorDiameter + 2 * horizontalSpacerWidth; + + int remeasuredHeight = 0; + final int numChildren = getChildCount(); + for (int i = 0; i < numChildren; i++) { + final View child = getChildAt(i); + if (child.getId() == R.id.biometric_icon_frame) { + final FrameLayout iconFrame = (FrameLayout) child; + final View icon = iconFrame.getChildAt(0); + + // Ensure that the icon is never larger than the sensor. + icon.measure( + MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST)); + + // Create a frame that's exactly the height of the sensor circle. + iconFrame.measure( + MeasureSpec.makeMeasureSpec(remeasuredWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY)); + } else if (child.getId() == R.id.space_above_icon || child.getId() == R.id.button_bar) { + // Adjust the width of the top spacer and button bar while preserving their heights. + child.measure( + MeasureSpec.makeMeasureSpec(remeasuredWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec( + child.getLayoutParams().height, MeasureSpec.EXACTLY)); + } else if (child.getId() == R.id.space_below_icon) { + // Adjust the bottom spacer height to align the fingerprint icon with the sensor. + child.measure( + MeasureSpec.makeMeasureSpec(remeasuredWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(bottomSpacerHeight, MeasureSpec.EXACTLY)); + } else { + // Use the remeasured width for all other child views. + child.measure( + MeasureSpec.makeMeasureSpec(remeasuredWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); + } + + if (child.getVisibility() != View.GONE) { + remeasuredHeight += child.getMeasuredHeight(); + } + } + + return new AuthDialog.LayoutParams(remeasuredWidth, remeasuredHeight); + } + + private int getViewHeightPx(@IdRes int viewId) { + final View view = findViewById(viewId); + return view != null ? view.getMeasuredHeight() : 0; + } + + private int getDialogMarginPx() { + return getResources().getDimensionPixelSize(R.dimen.biometric_dialog_border_padding); + } + + @NonNull + private static Insets getNavbarInsets(@Nullable WindowManager windowManager) { + return windowManager != null && windowManager.getCurrentWindowMetrics() != null + ? windowManager.getCurrentWindowMetrics().getWindowInsets() + .getInsets(WindowInsets.Type.navigationBars()) + : Insets.NONE; + } + + @NonNull + private static Rect getWindowBounds(@Nullable WindowManager windowManager) { + return windowManager != null && windowManager.getCurrentWindowMetrics() != null + ? windowManager.getCurrentWindowMetrics().getBounds() + : new Rect(); + } + + /** + * For devices in portrait orientation where the sensor is too high up, calculates the amount of + * padding necessary to center the biometric icon within the sensor's physical location. + */ + @VisibleForTesting + static int calculateBottomSpacerHeightForPortrait( + @NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayHeightPx, + int textIndicatorHeightPx, int buttonBarHeightPx, int dialogMarginPx, + int navbarBottomInsetPx) { + + final int sensorDistanceFromBottom = displayHeightPx + - sensorProperties.sensorLocationY + - sensorProperties.sensorRadius; + + final int spacerHeight = sensorDistanceFromBottom + - textIndicatorHeightPx + - buttonBarHeightPx + - dialogMarginPx + - navbarBottomInsetPx; + + Log.d(TAG, "Display height: " + displayHeightPx + + ", Distance from bottom: " + sensorDistanceFromBottom + + ", Bottom margin: " + dialogMarginPx + + ", Navbar bottom inset: " + navbarBottomInsetPx + + ", Bottom spacer height (portrait): " + spacerHeight); + + return spacerHeight; + } + + /** + * For devices in landscape orientation where the sensor is too high up, calculates the amount + * of padding necessary to center the biometric icon within the sensor's physical location. + */ + @VisibleForTesting + static int calculateBottomSpacerHeightForLandscape(int titleHeightPx, int subtitleHeightPx, + int descriptionHeightPx, int topSpacerHeightPx, int textIndicatorHeightPx, + int buttonBarHeightPx, int navbarBottomInsetPx) { + + final int dialogHeightAboveIcon = titleHeightPx + + subtitleHeightPx + + descriptionHeightPx + + topSpacerHeightPx; + + final int dialogHeightBelowIcon = textIndicatorHeightPx + buttonBarHeightPx; + + final int bottomSpacerHeight = dialogHeightAboveIcon + - dialogHeightBelowIcon + - navbarBottomInsetPx; + + Log.d(TAG, "Title height: " + titleHeightPx + + ", Subtitle height: " + subtitleHeightPx + + ", Description height: " + descriptionHeightPx + + ", Top spacer height: " + topSpacerHeightPx + + ", Text indicator height: " + textIndicatorHeightPx + + ", Button bar height: " + buttonBarHeightPx + + ", Navbar bottom inset: " + navbarBottomInsetPx + + ", Bottom spacer height (landscape): " + bottomSpacerHeight); + + return bottomSpacerHeight; + } + + /** + * For devices in landscape orientation where the sensor is too left/right, calculates the + * amount of padding necessary to center the biometric icon within the sensor's physical + * location. + */ + @VisibleForTesting + static int calculateHorizontalSpacerWidthForLandscape( + @NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayWidthPx, + int dialogMarginPx, int navbarHorizontalInsetPx) { + + final int sensorDistanceFromEdge = displayWidthPx + - sensorProperties.sensorLocationY + - sensorProperties.sensorRadius; + + final int horizontalPadding = sensorDistanceFromEdge + - dialogMarginPx + - navbarHorizontalInsetPx; + + Log.d(TAG, "Display width: " + displayWidthPx + + ", Distance from edge: " + sensorDistanceFromEdge + + ", Dialog margin: " + dialogMarginPx + + ", Navbar horizontal inset: " + navbarHorizontalInsetPx + + ", Horizontal spacer width (landscape): " + horizontalPadding); + + return horizontalPadding; + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java index 18206efefe9a..d59a865e2add 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java @@ -742,6 +742,7 @@ public abstract class AuthBiometricView extends LinearLayout { * @param height Height to constrain the measurements to. * @return See {@link AuthDialog.LayoutParams} */ + @NonNull AuthDialog.LayoutParams onMeasureInternal(int width, int height) { int totalHeight = 0; final int numChildren = getChildCount(); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 935f89343754..d05e9278762d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -32,8 +32,10 @@ import android.os.IBinder; import android.os.Looper; import android.os.UserManager; import android.util.Log; +import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; +import android.view.Surface; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; @@ -433,6 +435,29 @@ public class AuthContainerView extends LinearLayout + mConfig.mPromptInfo.getAuthenticators()); } + if (mBiometricView instanceof AuthBiometricUdfpsView) { + final int displayRotation = getDisplay().getRotation(); + switch (displayRotation) { + case Surface.ROTATION_0: + mPanelController.setPosition(AuthPanelController.POSITION_BOTTOM); + setScrollViewGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); + break; + case Surface.ROTATION_90: + mPanelController.setPosition(AuthPanelController.POSITION_RIGHT); + setScrollViewGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT); + break; + case Surface.ROTATION_270: + mPanelController.setPosition(AuthPanelController.POSITION_LEFT); + setScrollViewGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); + break; + default: + Log.e(TAG, "Unsupported display rotation: " + displayRotation); + mPanelController.setPosition(AuthPanelController.POSITION_BOTTOM); + setScrollViewGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); + break; + } + } + if (mConfig.mSkipIntro) { mContainerState = STATE_SHOWING; } else { @@ -476,6 +501,13 @@ public class AuthContainerView extends LinearLayout } } + private void setScrollViewGravity(int gravity) { + final FrameLayout.LayoutParams params = + (FrameLayout.LayoutParams) mBiometricScrollView.getLayoutParams(); + params.gravity = gravity; + mBiometricScrollView.setLayoutParams(params); + } + @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java index 11503fbd0b1d..fa50f895f83e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java @@ -18,6 +18,7 @@ package com.android.systemui.biometrics; import android.animation.AnimatorSet; import android.animation.ValueAnimator; +import android.annotation.IntDef; import android.content.Context; import android.graphics.Outline; import android.util.Log; @@ -27,10 +28,20 @@ import android.view.animation.AccelerateDecelerateInterpolator; import com.android.systemui.R; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Controls the back panel and its animations for the BiometricPrompt UI. */ public class AuthPanelController extends ViewOutlineProvider { + public static final int POSITION_BOTTOM = 1; + public static final int POSITION_LEFT = 2; + public static final int POSITION_RIGHT = 3; + + @IntDef({POSITION_BOTTOM, POSITION_LEFT, POSITION_RIGHT}) + @Retention(RetentionPolicy.SOURCE) + public @interface Position {} private static final String TAG = "BiometricPrompt/AuthPanelController"; private static final boolean DEBUG = false; @@ -38,6 +49,7 @@ public class AuthPanelController extends ViewOutlineProvider { private final Context mContext; private final View mPanelView; + @Position private int mPosition = POSITION_BOTTOM; private boolean mUseFullScreen; private int mContainerWidth; @@ -51,21 +63,44 @@ public class AuthPanelController extends ViewOutlineProvider { @Override public void getOutline(View view, Outline outline) { - final int left = (mContainerWidth - mContentWidth) / 2; - final int right = mContainerWidth - left; - - // If the content fits within the container, shrink the height to wrap the content. - // Otherwise, set the outline to be the display size minus the margin - the content within - // is scrollable. - final int top = mContentHeight < mContainerHeight - ? mContainerHeight - mContentHeight - mMargin - : mMargin; - - // TODO(b/139954942) Likely don't need to "+1" after we resolve the navbar styling. - final int bottom = mContainerHeight - mMargin + 1; + final int left = getLeftBound(mPosition); + final int right = left + mContentWidth; + + // If the content fits in the container, shrink the height to wrap it. Otherwise, expand to + // fill the display (minus the margin), since the content is scrollable. + final int top = getTopBound(mPosition); + final int bottom = Math.min(top + mContentHeight, mContainerHeight - mMargin); + outline.setRoundRect(left, top, right, bottom, mCornerRadius); } + private int getLeftBound(@Position int position) { + switch (position) { + case POSITION_BOTTOM: + return (mContainerWidth - mContentWidth) / 2; + case POSITION_LEFT: + return mMargin; + case POSITION_RIGHT: + return mContainerWidth - mContentWidth - mMargin; + default: + Log.e(TAG, "Unrecognized position: " + position); + return getLeftBound(POSITION_BOTTOM); + } + } + + private int getTopBound(@Position int position) { + switch (position) { + case POSITION_BOTTOM: + return Math.max(mContainerHeight - mContentHeight - mMargin, mMargin); + case POSITION_LEFT: + case POSITION_RIGHT: + return Math.max((mContainerHeight - mContentHeight) / 2, mMargin); + default: + Log.e(TAG, "Unrecognized position: " + position); + return getTopBound(POSITION_BOTTOM); + } + } + public void setContainerDimensions(int containerWidth, int containerHeight) { if (DEBUG) { Log.v(TAG, "Container Width: " + containerWidth + " Height: " + containerHeight); @@ -74,6 +109,10 @@ public class AuthPanelController extends ViewOutlineProvider { mContainerHeight = containerHeight; } + public void setPosition(@Position int position) { + mPosition = position; + } + public void setUseFullScreen(boolean fullScreen) { mUseFullScreen = fullScreen; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java index 43ecf6778022..2036150d3679 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java @@ -16,57 +16,63 @@ package com.android.systemui.biometrics; -import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.graphics.Canvas; -import android.graphics.PointF; import android.graphics.RectF; import android.util.AttributeSet; import android.widget.FrameLayout; -import com.android.systemui.doze.DozeReceiver; -import com.android.systemui.statusbar.phone.StatusBar; - /** * Base class for views containing UDFPS animations. Note that this is a FrameLayout so that we - * can support multiple child views drawing on the same region around the sensor location. + * can support multiple child views drawing in the same region around the sensor location. + * + * - hides animation view when pausing auth + * - sends illumination events to fingerprint drawable + * - sends sensor rect updates to fingerprint drawable + * - optionally can override dozeTimeTick to adjust views for burn-in mitigation */ -public abstract class UdfpsAnimationView extends FrameLayout implements DozeReceiver, - StatusBar.ExpansionChangedListener { - - private static final String TAG = "UdfpsAnimationView"; +abstract class UdfpsAnimationView extends FrameLayout { - @Nullable protected abstract UdfpsAnimation getUdfpsAnimation(); - - @NonNull private UdfpsView mParent; - @NonNull private RectF mSensorRect; private int mAlpha; + private boolean mPauseAuth; public UdfpsAnimationView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); - mSensorRect = new RectF(); - setWillNotDraw(false); } - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); + /** + * Fingerprint drawable + */ + abstract UdfpsDrawable getDrawable(); - if (getUdfpsAnimation() != null) { - final int alpha = mParent.shouldPauseAuth() ? mAlpha : 255; - getUdfpsAnimation().setAlpha(alpha); - getUdfpsAnimation().draw(canvas); - } + void onSensorRectUpdated(RectF bounds) { + getDrawable().onSensorRectUpdated(bounds); } - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); + void onIlluminationStarting() { + getDrawable().setIlluminationShowing(true); + getDrawable().invalidateSelf(); + } + + void onIlluminationStopped() { + getDrawable().setIlluminationShowing(false); + getDrawable().invalidateSelf(); + } - if (getUdfpsAnimation() != null) { - getUdfpsAnimation().onDestroy(); + /** + * @return true if changed + */ + boolean setPauseAuth(boolean pauseAuth) { + if (pauseAuth != mPauseAuth) { + mPauseAuth = pauseAuth; + updateAlpha(); + return true; } + return false; + } + + private void updateAlpha() { + getDrawable().setAlpha(mPauseAuth ? mAlpha : 255); } private int expansionToAlpha(float expansion) { @@ -81,76 +87,15 @@ public abstract class UdfpsAnimationView extends FrameLayout implements DozeRece return (int) ((1 - percent) * 255); } - void onIlluminationStarting() { - if (getUdfpsAnimation() == null) { - return; - } - - getUdfpsAnimation().setIlluminationShowing(true); - postInvalidate(); - } - - void onIlluminationStopped() { - if (getUdfpsAnimation() == null) { - return; - } - - getUdfpsAnimation().setIlluminationShowing(false); - postInvalidate(); - } - - void setParent(@NonNull UdfpsView parent) { - mParent = parent; - } - - void onSensorRectUpdated(@NonNull RectF sensorRect) { - mSensorRect = sensorRect; - if (getUdfpsAnimation() != null) { - getUdfpsAnimation().onSensorRectUpdated(mSensorRect); - } - } - - void updateColor() { - if (getUdfpsAnimation() != null) { - getUdfpsAnimation().updateColor(); - } - postInvalidate(); - } - - @Override - public void dozeTimeTick() { - if (getUdfpsAnimation() instanceof DozeReceiver) { - ((DozeReceiver) getUdfpsAnimation()).dozeTimeTick(); - } - } - - @Override public void onExpansionChanged(float expansion, boolean expanded) { mAlpha = expansionToAlpha(expansion); - postInvalidate(); - } - - public int getPaddingX() { - if (getUdfpsAnimation() == null) { - return 0; - } - return getUdfpsAnimation().getPaddingX(); - } - - public int getPaddingY() { - if (getUdfpsAnimation() == null) { - return 0; - } - return getUdfpsAnimation().getPaddingY(); + updateAlpha(); } /** - * @return the amount of translation needed if the view currently requires the user to touch - * somewhere other than the exact center of the sensor. For example, this can happen - * during guided enrollment. + * @return true if handled */ - @NonNull - PointF getTouchTranslation() { - return new PointF(0, 0); + boolean dozeTimeTick() { + return false; } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java new file mode 100644 index 000000000000..b6d80ba14dc0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java @@ -0,0 +1,167 @@ +/* + * 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.biometrics; + +import static com.android.systemui.statusbar.StatusBarState.FULLSCREEN_USER_SWITCHER; +import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; +import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED; + +import android.annotation.NonNull; +import android.graphics.PointF; +import android.graphics.RectF; + +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.util.ViewController; + +/** + * Handles: + * 1. registering for listeners when its view is attached and unregistering on view detached + * 2. pausing udfps when fingerprintManager may still be running but we temporarily want to hide + * the affordance. this allows us to fade the view in and out nicely (see shouldPauseAuth) + * 3. sending events to its view including: + * - illumination events + * - sensor position changes + * - doze time event + */ +abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView> + extends ViewController<T> { + @NonNull final StatusBarStateController mStatusBarStateController; + @NonNull final StatusBar mStatusBar; + + private boolean mNotificationShadeExpanded; + private int mStatusBarState; + + protected UdfpsAnimationViewController( + T view, + StatusBarStateController statusBarStateController, + StatusBar statusBar) { + super(view); + mStatusBarStateController = statusBarStateController; + mStatusBar = statusBar; + } + + @Override + protected void onViewAttached() { + mStatusBarStateController.addCallback(mStateListener); + mStateListener.onStateChanged(mStatusBarStateController.getState()); + mStatusBar.addExpansionChangedListener(mStatusBarExpansionChangedListener); + } + + @Override + protected void onViewDetached() { + mStatusBarStateController.removeCallback(mStateListener); + mStatusBar.removeExpansionChangedListener(mStatusBarExpansionChangedListener); + } + + /** + * Returns true if the fingerprint manager is running but we want to temporarily pause + * authentication. + */ + boolean shouldPauseAuth() { + return (mNotificationShadeExpanded && mStatusBarState != KEYGUARD) + || mStatusBarState == SHADE_LOCKED + || mStatusBarState == FULLSCREEN_USER_SWITCHER; + } + + /** + * Send pause auth update to our view. + */ + void updatePauseAuth() { + if (mView.setPauseAuth(shouldPauseAuth())) { + mView.postInvalidate(); + } + } + + /** + * Send sensor position change to our view. This rect contains paddingX and paddingY. + */ + void onSensorRectUpdated(RectF sensorRect) { + mView.onSensorRectUpdated(sensorRect); + } + + /** + * Send dozeTimeTick to view in case it wants to handle its burn-in offset. + */ + void dozeTimeTick() { + if (mView.dozeTimeTick()) { + mView.postInvalidate(); + } + } + + /** + * @return the amount of translation needed if the view currently requires the user to touch + * somewhere other than the exact center of the sensor. For example, this can happen + * during guided enrollment. + */ + PointF getTouchTranslation() { + return new PointF(0, 0); + } + + /** + * X-Padding to add to left and right of the sensor rectangle area to increase the size of our + * window to draw within. + * @return + */ + int getPaddingX() { + return 0; + } + + /** + * Y-Padding to add to top and bottom of the sensor rectangle area to increase the size of our + * window to draw within. + */ + int getPaddingY() { + return 0; + } + + /** + * Udfps has started illuminating and the fingerprint manager is working on authenticating. + */ + void onIlluminationStarting() { + mView.onIlluminationStarting(); + mView.postInvalidate(); + } + + /** + * Udfps has stopped illuminating and the fingerprint manager is no longer attempting to + * authenticate. + */ + void onIlluminationStopped() { + mView.onIlluminationStopped(); + mView.postInvalidate(); + } + + private final StatusBar.ExpansionChangedListener mStatusBarExpansionChangedListener = + new StatusBar.ExpansionChangedListener() { + @Override + public void onExpansionChanged(float expansion, boolean expanded) { + mNotificationShadeExpanded = expanded; + mView.onExpansionChanged(expansion, expanded); + updatePauseAuth(); + } + }; + + private final StatusBarStateController.StateListener mStateListener = + new StatusBarStateController.StateListener() { + @Override + public void onStateChanged(int newState) { + mStatusBarState = newState; + updatePauseAuth(); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java deleted file mode 100644 index 543df33dd5d7..000000000000 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.biometrics; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.graphics.PointF; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; - -import com.android.systemui.R; - -/** - * Class that coordinates non-HBM animations during enrollment. - */ -public class UdfpsAnimationViewEnroll extends UdfpsAnimationView - implements UdfpsEnrollHelper.Listener { - - private static final String TAG = "UdfpsAnimationViewEnroll"; - - @NonNull private UdfpsAnimationEnroll mUdfpsAnimation; - @NonNull private UdfpsProgressBar mProgressBar; - @Nullable private UdfpsEnrollHelper mEnrollHelper; - - @NonNull - @Override - protected UdfpsAnimation getUdfpsAnimation() { - return mUdfpsAnimation; - } - - public UdfpsAnimationViewEnroll(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - mUdfpsAnimation = new UdfpsAnimationEnroll(context); - } - - public void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) { - mEnrollHelper = helper; - mUdfpsAnimation.setEnrollHelper(helper); - } - - @Override - protected void onFinishInflate() { - mProgressBar = findViewById(R.id.progress_bar); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - if (mEnrollHelper == null) { - Log.e(TAG, "Enroll helper is null"); - return; - } - - if (mEnrollHelper.shouldShowProgressBar()) { - mProgressBar.setVisibility(View.VISIBLE); - - // Only need enrollment updates if the progress bar is showing :) - mEnrollHelper.setListener(this); - } - } - - @Override - public void onEnrollmentProgress(int remaining, int totalSteps) { - final int interpolatedProgress = mProgressBar.getMax() - * Math.max(0, totalSteps + 1 - remaining) / (totalSteps + 1); - - mProgressBar.setProgress(interpolatedProgress, true); - } - - @NonNull - @Override - PointF getTouchTranslation() { - if (!mEnrollHelper.isCenterEnrollmentComplete()) { - return new PointF(0, 0); - } else { - return mEnrollHelper.getNextGuidedEnrollmentPoint(); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewBp.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java index 515b442b61f6..70be907228c8 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewBp.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java @@ -24,19 +24,22 @@ import androidx.annotation.Nullable; /** * Class that coordinates non-HBM animations during BiometricPrompt. * + * Currently doesn't draw anything. + * * Note that {@link AuthBiometricUdfpsView} also shows UDFPS animations. At some point we should - * de-dupe this if necessary. This will probably happen once the top-level TODO in UdfpsController - * is completed (inflate operation-specific views, instead of inflating generic udfps_view and - * adding operation-specific animations to it). + * de-dupe this if necessary. */ -public class UdfpsAnimationViewBp extends UdfpsAnimationView { - public UdfpsAnimationViewBp(Context context, @Nullable AttributeSet attrs) { +public class UdfpsBpView extends UdfpsAnimationView { + private UdfpsFpDrawable mFingerprintDrawable; + + public UdfpsBpView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); + // Drawable isn't ever added to the view, so we don't currently show anything + mFingerprintDrawable = new UdfpsFpDrawable(mContext); } - @Nullable @Override - protected UdfpsAnimation getUdfpsAnimation() { - return null; + UdfpsDrawable getDrawable() { + return mFingerprintDrawable; } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java new file mode 100644 index 000000000000..b712c655a6e7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics; + +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.phone.StatusBar; + +/** + * Class that coordinates non-HBM animations for biometric prompt. + */ +class UdfpsBpViewController extends UdfpsAnimationViewController<UdfpsBpView> { + protected UdfpsBpViewController( + UdfpsBpView view, + StatusBarStateController statusBarStateController, + StatusBar statusBar) { + super(view, statusBarStateController, statusBar); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 1d789ca15dfb..94aeb73c4b42 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -31,9 +31,9 @@ import android.graphics.RectF; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IUdfpsOverlayController; -import android.os.SystemClock; import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; import android.os.RemoteException; +import android.os.SystemClock; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; @@ -195,17 +195,6 @@ public class UdfpsController implements DozeReceiver, HbmCallback { } } - @VisibleForTesting final StatusBar.ExpansionChangedListener mStatusBarExpansionListener = - (expansion, expanded) -> mView.onExpansionChanged(expansion, expanded); - - @VisibleForTesting final StatusBarStateController.StateListener mStatusBarStateListener = - new StatusBarStateController.StateListener() { - @Override - public void onStateChanged(int newState) { - mView.onStateChanged(newState); - } - }; - private static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) { final float vx = tracker.getXVelocity(pointerId); final float vy = tracker.getYVelocity(pointerId); @@ -360,10 +349,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { @Override public void dozeTimeTick() { - if (mView == null) { - return; + if (mView != null) { + mView.dozeTimeTick(); } - mView.dozeTimeTick(); } /** @@ -387,7 +375,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback { } } - private WindowManager.LayoutParams computeLayoutParams(@Nullable UdfpsAnimationView animation) { + private WindowManager.LayoutParams computeLayoutParams( + @Nullable UdfpsAnimationViewController animation) { final int paddingX = animation != null ? animation.getPaddingX() : 0; final int paddingY = animation != null ? animation.getPaddingY() : 0; @@ -438,19 +427,13 @@ public class UdfpsController implements DozeReceiver, HbmCallback { mFgExecutor.execute(() -> { if (mView == null) { try { - Log.v(TAG, "showUdfpsOverlay | adding window"); - // TODO: Eventually we should refactor the code to inflate an - // operation-specific view here, instead of inflating a generic udfps_view - // and adding operation-specific animations to it. + Log.v(TAG, "showUdfpsOverlay | adding window reason=" + reason); mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false); mView.setSensorProperties(mSensorProps); mView.setHbmCallback(this); - - final UdfpsAnimationView animation = getUdfpsAnimationViewForReason(reason); - mView.setAnimationView(animation); - - mStatusBar.addExpansionChangedListener(mStatusBarExpansionListener); - mStatusBarStateController.addCallback(mStatusBarStateListener); + UdfpsAnimationViewController animation = inflateUdfpsAnimation(reason); + animation.init(); + mView.setAnimationViewController(animation); mWindowManager.addView(mView, computeLayoutParams(animation)); mView.setOnTouchListener(mOnTouchListener); @@ -463,40 +446,46 @@ public class UdfpsController implements DozeReceiver, HbmCallback { }); } - @NonNull - private UdfpsAnimationView getUdfpsAnimationViewForReason(int reason) { - Log.d(TAG, "getUdfpsAnimationForReason: " + reason); - - final LayoutInflater inflater = LayoutInflater.from(mContext); - + private UdfpsAnimationViewController inflateUdfpsAnimation(int reason) { switch (reason) { case IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR: - case IUdfpsOverlayController.REASON_ENROLL_ENROLLING: { - final UdfpsAnimationViewEnroll view = (UdfpsAnimationViewEnroll) - inflater.inflate(R.layout.udfps_animation_view_enroll, null, false); - view.setEnrollHelper(mServerRequest.mEnrollHelper); - return view; - } - - case IUdfpsOverlayController.REASON_AUTH_BP: { - final UdfpsAnimationViewBp view = (UdfpsAnimationViewBp) - inflater.inflate(R.layout.udfps_animation_view_bp, null, false); - return view; - } - - case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD: { - final UdfpsAnimationViewKeyguard view = (UdfpsAnimationViewKeyguard) - inflater.inflate(R.layout.udfps_animation_view_keyguard, null, false); - view.setStatusBarStateController(mStatusBarStateController); - return view; - } - - case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER: { - final UdfpsAnimationViewFpmOther view = (UdfpsAnimationViewFpmOther) - inflater.inflate(R.layout.udfps_animation_view_fpm_other, null, false); - return view; - } - + case IUdfpsOverlayController.REASON_ENROLL_ENROLLING: + UdfpsEnrollView enrollView = (UdfpsEnrollView) mInflater.inflate( + R.layout.udfps_enroll_view, null); + mView.addView(enrollView); + return new UdfpsEnrollViewController( + enrollView, + mServerRequest.mEnrollHelper, + mStatusBarStateController, + mStatusBar + ); + case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD: + UdfpsKeyguardView keyguardView = (UdfpsKeyguardView) + mInflater.inflate(R.layout.udfps_keyguard_view, null); + mView.addView(keyguardView); + return new UdfpsKeyguardViewController( + keyguardView, + mStatusBarStateController, + mStatusBar + ); + case IUdfpsOverlayController.REASON_AUTH_BP: + // note: empty controller, currently shows no visual affordance + UdfpsBpView bpView = (UdfpsBpView) mInflater.inflate(R.layout.udfps_bp_view, null); + mView.addView(bpView); + return new UdfpsBpViewController( + bpView, + mStatusBarStateController, + mStatusBar + ); + case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER: + UdfpsFpmOtherView authOtherView = (UdfpsFpmOtherView) + mInflater.inflate(R.layout.udfps_fpm_other_view, null); + mView.addView(authOtherView); + return new UdfpsFpmOtherViewController( + authOtherView, + mStatusBarStateController, + mStatusBar + ); default: Log.d(TAG, "Animation for reason " + reason + " not supported yet"); return null; @@ -509,11 +498,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { Log.v(TAG, "hideUdfpsOverlay | removing window"); // Reset the controller back to its starting state. onFingerUp(); - - mStatusBar.removeExpansionChangedListener(mStatusBarExpansionListener); - mStatusBarStateController.removeCallback(mStatusBarStateListener); - mWindowManager.removeView(mView); + mView.setOnTouchListener(null); + mView.setAnimationViewController(null); mView = null; } else { Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden"); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java index a51b6fd16445..13d31cb87fdc 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java @@ -17,10 +17,10 @@ package com.android.systemui.biometrics; import android.content.Context; +import android.graphics.ColorFilter; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; -import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -28,24 +28,24 @@ import androidx.annotation.Nullable; import com.android.systemui.R; /** - * Abstract base class for animations that should be drawn when the finger is not touching the + * Abstract base class for drawable displayed when the finger is not touching the * sensor area. */ -public abstract class UdfpsAnimation extends Drawable { - protected abstract void updateColor(); - protected abstract void onDestroy(); - +public abstract class UdfpsDrawable extends Drawable { @NonNull protected final Context mContext; @NonNull protected final Drawable mFingerprintDrawable; - @Nullable private View mView; private boolean mIlluminationShowing; - public UdfpsAnimation(@NonNull Context context) { + int mAlpha = 255; // 0 - 255 + public UdfpsDrawable(@NonNull Context context) { mContext = context; mFingerprintDrawable = context.getResources().getDrawable(R.drawable.ic_fingerprint, null); mFingerprintDrawable.mutate(); } + /** + * @param sensorRect the rect coordinates for the sensor area + */ public void onSensorRectUpdated(@NonNull RectF sensorRect) { final int margin = (int) sensorRect.height() / 8; @@ -56,17 +56,17 @@ public abstract class UdfpsAnimation extends Drawable { updateFingerprintIconBounds(bounds); } + /** + * Bounds for the fingerprint icon + */ protected void updateFingerprintIconBounds(@NonNull Rect bounds) { mFingerprintDrawable.setBounds(bounds); } @Override public void setAlpha(int alpha) { - mFingerprintDrawable.setAlpha(alpha); - } - - public void setAnimationView(UdfpsAnimationView view) { - mView = view; + mAlpha = alpha; + mFingerprintDrawable.setAlpha(mAlpha); } boolean isIlluminationShowing() { @@ -77,23 +77,12 @@ public abstract class UdfpsAnimation extends Drawable { mIlluminationShowing = showing; } - /** - * @return The amount of padding that's needed on each side of the sensor, in pixels. - */ - public int getPaddingX() { - return 0; + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { } - /** - * @return The amount of padding that's needed on each side of the sensor, in pixels. - */ - public int getPaddingY() { + @Override + public int getOpacity() { return 0; } - - protected void postInvalidateView() { - if (mView != null) { - mView.postInvalidate(); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java index 015a598e972b..d80e085bdc70 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.Rect; @@ -33,23 +32,23 @@ import androidx.annotation.Nullable; import com.android.systemui.R; /** - * UDFPS animations that should be shown when enrolling. + * UDFPS fingerprint drawable that is shown when enrolling */ -public class UdfpsAnimationEnroll extends UdfpsAnimation { +public class UdfpsEnrollDrawable extends UdfpsDrawable { private static final String TAG = "UdfpsAnimationEnroll"; private static final float SHADOW_RADIUS = 5.f; - private static final float PROGRESS_BAR_RADIUS = 140.f; + static final float PROGRESS_BAR_RADIUS = 140.f; @NonNull private final Drawable mMovingTargetFpIcon; @NonNull private final Paint mSensorPaint; @NonNull private final Paint mBlueFill; - @NonNull private final Paint mBlueStroke;; + @NonNull private final Paint mBlueStroke; @Nullable private RectF mSensorRect; @Nullable private UdfpsEnrollHelper mEnrollHelper; - UdfpsAnimationEnroll(@NonNull Context context) { + UdfpsEnrollDrawable(@NonNull Context context) { super(context); mSensorPaint = new Paint(0 /* flags */); @@ -72,20 +71,12 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation { mMovingTargetFpIcon = context.getResources().getDrawable(R.drawable.ic_fingerprint, null); mMovingTargetFpIcon.setTint(Color.WHITE); mMovingTargetFpIcon.mutate(); - } - - void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) { - mEnrollHelper = helper; - } - @Override - protected void updateColor() { mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon)); } - @Override - protected void onDestroy() { - + void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) { + mEnrollHelper = helper; } @Override @@ -98,6 +89,7 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation { protected void updateFingerprintIconBounds(@NonNull Rect bounds) { super.updateFingerprintIconBounds(bounds); mMovingTargetFpIcon.setBounds(bounds); + invalidateSelf(); } @Override @@ -117,7 +109,7 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation { // Draw moving target if (mEnrollHelper.isCenterEnrollmentComplete()) { - mFingerprintDrawable.setAlpha(64); + mFingerprintDrawable.setAlpha(mAlpha == 255 ? 64 : mAlpha); canvas.save(); final PointF point = mEnrollHelper.getNextGuidedEnrollmentPoint(); @@ -130,33 +122,16 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation { mMovingTargetFpIcon.draw(canvas); canvas.restore(); } else { - mFingerprintDrawable.setAlpha(255); + mFingerprintDrawable.setAlpha(mAlpha); } } @Override - public int getPaddingX() { - return (int) Math.ceil(PROGRESS_BAR_RADIUS); - } - - @Override - public int getPaddingY() { - return (int) Math.ceil(PROGRESS_BAR_RADIUS); - } - - @Override public void setAlpha(int alpha) { super.setAlpha(alpha); mSensorPaint.setAlpha(alpha); - } - - @Override - public void setColorFilter(@Nullable ColorFilter colorFilter) { - - } - - @Override - public int getOpacity() { - return 0; + mBlueFill.setAlpha(alpha); + mBlueStroke.setAlpha(alpha); + invalidateSelf(); } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java index 14eca1b1cb2c..62058a965c09 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java @@ -100,13 +100,13 @@ public class UdfpsEnrollHelper { } - void setListener(@NonNull Listener listener) { + void setListener(Listener listener) { mListener = listener; // Only notify during setListener if enrollment is already in progress, so the progress // bar can be updated. If enrollment has not started yet, the progress bar will be empty // anyway. - if (mTotalSteps != -1) { + if (mListener != null && mTotalSteps != -1) { mListener.onEnrollmentProgress(mRemainingSteps, mTotalSteps); } } @@ -122,6 +122,8 @@ public class UdfpsEnrollHelper { @NonNull PointF getNextGuidedEnrollmentPoint() { final int index = mLocationsEnrolled - NUM_CENTER_TOUCHES; - return mGuidedEnrollmentPoints.get(index % mGuidedEnrollmentPoints.size()); + final PointF originalPoint = mGuidedEnrollmentPoints + .get(index % mGuidedEnrollmentPoints.size()); + return new PointF(originalPoint.x * 0.5f, originalPoint.y * 0.5f); } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java index 7d0b3e59feb1..7985d95c7c61 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java @@ -18,32 +18,36 @@ package com.android.systemui.biometrics; import android.content.Context; import android.util.AttributeSet; +import android.widget.ImageView; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.R; /** - * Class that coordinates non-HBM animations during keyguard authentication. + * View corresponding with udfps_enroll_view.xml */ -public class UdfpsAnimationViewKeyguard extends UdfpsAnimationView { - @Nullable private UdfpsAnimationKeyguard mAnimation; +public class UdfpsEnrollView extends UdfpsAnimationView { + private final UdfpsEnrollDrawable mFingerprintDrawable; + private ImageView mFingerprintView; - public UdfpsAnimationViewKeyguard(Context context, @Nullable AttributeSet attrs) { + public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); + mFingerprintDrawable = new UdfpsEnrollDrawable(mContext); } - void setStatusBarStateController(@NonNull StatusBarStateController statusBarStateController) { - if (mAnimation == null) { - mAnimation = new UdfpsAnimationKeyguard(getContext(), statusBarStateController); - mAnimation.setAnimationView(this); - } + @Override + protected void onFinishInflate() { + mFingerprintView = findViewById(R.id.udfps_enroll_animation_fp_view); + mFingerprintView.setImageDrawable(mFingerprintDrawable); } - @Nullable @Override - protected UdfpsAnimation getUdfpsAnimation() { - return mAnimation; + public UdfpsDrawable getDrawable() { + return mFingerprintDrawable; + } + + void setEnrollHelper(UdfpsEnrollHelper enrollHelper) { + mFingerprintDrawable.setEnrollHelper(enrollHelper); } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java new file mode 100644 index 000000000000..da8d712ebbdc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java @@ -0,0 +1,92 @@ +/* + * 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.biometrics; + +import android.annotation.NonNull; +import android.graphics.PointF; +import android.view.View; + +import com.android.systemui.R; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.phone.StatusBar; + +/** + * Class that coordinates non-HBM animations during enrollment. + */ +public class UdfpsEnrollViewController extends UdfpsAnimationViewController<UdfpsEnrollView> { + @NonNull private final UdfpsProgressBar mProgressBar; + @NonNull private final UdfpsEnrollHelper mEnrollHelper; + + protected UdfpsEnrollViewController( + UdfpsEnrollView view, + @NonNull UdfpsEnrollHelper enrollHelper, + StatusBarStateController statusBarStateController, + StatusBar statusBar) { + super(view, statusBarStateController, statusBar); + mEnrollHelper = enrollHelper; + mProgressBar = mView.findViewById(R.id.progress_bar); + mView.setEnrollHelper(mEnrollHelper); + } + + @Override + protected void onViewAttached() { + super.onViewAttached(); + if (mEnrollHelper.shouldShowProgressBar()) { + mProgressBar.setVisibility(View.VISIBLE); + + // Only need enrollment updates if the progress bar is showing :) + mEnrollHelper.setListener(mEnrollHelperListener); + } + } + + @Override + protected void onViewDetached() { + super.onViewDetached(); + mEnrollHelper.setListener(null); + } + + @NonNull + @Override + public PointF getTouchTranslation() { + if (!mEnrollHelper.isCenterEnrollmentComplete()) { + return new PointF(0, 0); + } else { + return mEnrollHelper.getNextGuidedEnrollmentPoint(); + } + } + + @Override + public int getPaddingX() { + return (int) Math.ceil(UdfpsEnrollDrawable.PROGRESS_BAR_RADIUS); + } + + @Override + public int getPaddingY() { + return (int) Math.ceil(UdfpsEnrollDrawable.PROGRESS_BAR_RADIUS); + } + + private final UdfpsEnrollHelper.Listener mEnrollHelperListener = + new UdfpsEnrollHelper.Listener() { + @Override + public void onEnrollmentProgress(int remaining, int totalSteps) { + final int interpolatedProgress = mProgressBar.getMax() + * Math.max(0, totalSteps + 1 - remaining) / (totalSteps + 1); + + mProgressBar.setProgress(interpolatedProgress, true); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java index ef7a34000841..09b6fabbdd15 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java @@ -18,32 +18,19 @@ package com.android.systemui.biometrics; import android.content.Context; import android.graphics.Canvas; -import android.graphics.ColorFilter; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; /** - * UDFPS animations that should be shown when authenticating via FingerprintManager, excluding - * keyguard. + * Draws udfps fingerprint if sensor isn't illuminating. */ -public class UdfpsAnimationFpmOther extends UdfpsAnimation { +public class UdfpsFpDrawable extends UdfpsDrawable { - UdfpsAnimationFpmOther(@NonNull Context context) { + UdfpsFpDrawable(@NonNull Context context) { super(context); } @Override - protected void updateColor() { - - } - - @Override - protected void onDestroy() { - - } - - @Override public void draw(@NonNull Canvas canvas) { if (isIlluminationShowing()) { return; @@ -51,14 +38,4 @@ public class UdfpsAnimationFpmOther extends UdfpsAnimation { mFingerprintDrawable.draw(canvas); } - - @Override - public void setColorFilter(@Nullable ColorFilter colorFilter) { - - } - - @Override - public int getOpacity() { - return 0; - } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java index 3d2f5a0fe5cf..85f16068188e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java @@ -18,25 +18,32 @@ package com.android.systemui.biometrics; import android.content.Context; import android.util.AttributeSet; +import android.widget.ImageView; import androidx.annotation.Nullable; +import com.android.systemui.R; + /** - * Class that coordinates non-HBM animations during other usage of FingerprintManager (not - * including Keyguard). + * View corresponding with udfps_fpm_other_view.xml */ -public class UdfpsAnimationViewFpmOther extends UdfpsAnimationView { - - private final UdfpsAnimationFpmOther mAnimation; +public class UdfpsFpmOtherView extends UdfpsAnimationView { + private final UdfpsFpDrawable mFingerprintDrawable; + private ImageView mFingerprintView; - public UdfpsAnimationViewFpmOther(Context context, @Nullable AttributeSet attrs) { + public UdfpsFpmOtherView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); - mAnimation = new UdfpsAnimationFpmOther(context); + mFingerprintDrawable = new UdfpsFpDrawable(context); + } + + @Override + protected void onFinishInflate() { + mFingerprintView = findViewById(R.id.udfps_fpm_other_fp_view); + mFingerprintView.setImageDrawable(mFingerprintDrawable); } - @Nullable @Override - protected UdfpsAnimation getUdfpsAnimation() { - return mAnimation; + UdfpsDrawable getDrawable() { + return mFingerprintDrawable; } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java new file mode 100644 index 000000000000..587501bd1aa5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.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.systemui.biometrics; + +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.phone.StatusBar; + +/** + * Class that coordinates non-HBM animations for non keyguard, enrollment or biometric prompt + * states. + * + * Currently only shows the fp drawable. + */ +class UdfpsFpmOtherViewController extends UdfpsAnimationViewController<UdfpsFpmOtherView> { + protected UdfpsFpmOtherViewController( + UdfpsFpmOtherView view, + StatusBarStateController statusBarStateController, + StatusBar statusBar) { + super(view, statusBarStateController, statusBar); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java index 5f268cfa8fa5..b0c5da09d916 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java @@ -21,28 +21,25 @@ import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.ColorFilter; import android.util.MathUtils; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.android.internal.graphics.ColorUtils; import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.doze.DozeReceiver; -import com.android.systemui.plugins.statusbar.StatusBarStateController; /** * UDFPS animations that should be shown when authenticating on keyguard. */ -public class UdfpsAnimationKeyguard extends UdfpsAnimation implements DozeReceiver, - StatusBarStateController.StateListener { +public class UdfpsKeyguardDrawable extends UdfpsDrawable implements DozeReceiver { private static final String TAG = "UdfpsAnimationKeyguard"; + private final int mLockScreenColor; + private final int mAmbientDisplayColor; @NonNull private final Context mContext; - @NonNull private final StatusBarStateController mStatusBarStateController; private final int mMaxBurnInOffsetX; private final int mMaxBurnInOffsetY; @@ -51,18 +48,19 @@ public class UdfpsAnimationKeyguard extends UdfpsAnimation implements DozeReceiv private float mBurnInOffsetX; private float mBurnInOffsetY; - UdfpsAnimationKeyguard(@NonNull Context context, - @NonNull StatusBarStateController statusBarStateController) { + UdfpsKeyguardDrawable(@NonNull Context context) { super(context); mContext = context; - mStatusBarStateController = statusBarStateController; + // TODO: move burn-in to view mMaxBurnInOffsetX = context.getResources() .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x); mMaxBurnInOffsetY = context.getResources() .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y); - statusBarStateController.addCallback(this); + mLockScreenColor = Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor); + mAmbientDisplayColor = Color.WHITE; + updateAodPositionAndColor(); } private void updateAodPositionAndColor() { @@ -74,18 +72,14 @@ public class UdfpsAnimationKeyguard extends UdfpsAnimation implements DozeReceiv getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */) - mMaxBurnInOffsetY, mInterpolatedDarkAmount); - updateColor(); - postInvalidateView(); - } - @Override - public void dozeTimeTick() { - updateAodPositionAndColor(); + mFingerprintDrawable.setTint(ColorUtils.blendARGB(mLockScreenColor, + mAmbientDisplayColor, mInterpolatedDarkAmount)); + invalidateSelf(); } @Override - public void onDozeAmountChanged(float linear, float eased) { - mInterpolatedDarkAmount = eased; + public void dozeTimeTick() { updateAodPositionAndColor(); } @@ -94,34 +88,11 @@ public class UdfpsAnimationKeyguard extends UdfpsAnimation implements DozeReceiv if (isIlluminationShowing()) { return; } - - canvas.save(); - canvas.translate(mBurnInOffsetX, mBurnInOffsetY); mFingerprintDrawable.draw(canvas); - canvas.restore(); } - @Override - public void setColorFilter(@Nullable ColorFilter colorFilter) { - - } - - @Override - public int getOpacity() { - return 0; - } - - @Override - protected void updateColor() { - final int lockScreenIconColor = Utils.getColorAttrDefaultColor(mContext, - R.attr.wallpaperTextColor); - final int ambientDisplayIconColor = Color.WHITE; - mFingerprintDrawable.setTint(ColorUtils.blendARGB(lockScreenIconColor, - ambientDisplayIconColor, mInterpolatedDarkAmount)); - } - - @Override - protected void onDestroy() { - mStatusBarStateController.removeCallback(this); + void onDozeAmountChanged(float linear, float eased) { + mInterpolatedDarkAmount = eased; + updateAodPositionAndColor(); } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java new file mode 100644 index 000000000000..6a9356034d22 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java @@ -0,0 +1,60 @@ +/* + * 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.biometrics; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ImageView; + +import androidx.annotation.Nullable; + +import com.android.systemui.R; + +/** + * View corresponding with udfps_keyguard_view.xml + */ +public class UdfpsKeyguardView extends UdfpsAnimationView { + private final UdfpsKeyguardDrawable mFingerprintDrawable; + private ImageView mFingerprintView; + + public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + mFingerprintDrawable = new UdfpsKeyguardDrawable(mContext); + } + + @Override + protected void onFinishInflate() { + mFingerprintView = findViewById(R.id.udfps_keyguard_animation_fp_view); + mFingerprintView.setImageDrawable(mFingerprintDrawable); + } + + @Override + public UdfpsDrawable getDrawable() { + return mFingerprintDrawable; + } + + @Override + public boolean dozeTimeTick() { + // TODO: burnin + mFingerprintDrawable.dozeTimeTick(); + return true; + } + + void onDozeAmountChanged(float linear, float eased) { + mFingerprintDrawable.onDozeAmountChanged(linear, eased); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java new file mode 100644 index 000000000000..14bb3fee1174 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics; + +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.phone.StatusBar; + +/** + * Class that coordinates non-HBM animations during keyguard authentication. + */ +public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<UdfpsKeyguardView> { + private boolean mForceShow; + + protected UdfpsKeyguardViewController( + UdfpsKeyguardView view, + StatusBarStateController statusBarStateController, + StatusBar statusBar) { + super(view, statusBarStateController, statusBar); + } + + @Override + protected void onViewAttached() { + super.onViewAttached(); + mStatusBarStateController.addCallback(mStateListener); + final float dozeAmount = mStatusBarStateController.getDozeAmount(); + mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount); + } + + @Override + protected void onViewDetached() { + super.onViewDetached(); + mStatusBarStateController.removeCallback(mStateListener); + } + + /** + * Overrides non-force show logic in shouldPauseAuth to still auth. + */ + private void forceShow(boolean forceShow) { + if (mForceShow == forceShow) { + return; + } + + mForceShow = forceShow; + updatePauseAuth(); + // TODO: animate show/hide background protection + } + + /** + * Returns true if the fingerprint manager is running but we want to temporarily pause + * authentication. On the keyguard, we may want to show udfps when the shade + * is expanded, so this can be overridden with the forceShow method. + */ + public boolean shouldPauseAuth() { + if (mForceShow) { + return false; + } + return super.shouldPauseAuth(); + } + + private final StatusBarStateController.StateListener mStateListener = + new StatusBarStateController.StateListener() { + @Override + public void onDozeAmountChanged(float linear, float eased) { + mView.onDozeAmountChanged(linear, eased); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java index a52bddc1dcd5..42d0d8438e15 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java @@ -16,10 +16,6 @@ package com.android.systemui.biometrics; -import static com.android.systemui.statusbar.StatusBarState.FULLSCREEN_USER_SWITCHER; -import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; -import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED; - import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -39,15 +35,12 @@ import android.widget.FrameLayout; import com.android.systemui.R; import com.android.systemui.doze.DozeReceiver; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.phone.StatusBar; /** * A view containing 1) A SurfaceView for HBM, and 2) A normal drawable view for all other * animations. */ -public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIlluminator, - StatusBarStateController.StateListener, StatusBar.ExpansionChangedListener { +public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIlluminator { private static final String TAG = "UdfpsView"; private static final int DEBUG_TEXT_SIZE_PX = 32; @@ -56,7 +49,7 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin @NonNull private final Paint mDebugTextPaint; @NonNull private UdfpsSurfaceView mHbmSurfaceView; - @Nullable private UdfpsAnimationView mAnimationView; + @Nullable private UdfpsAnimationViewController mAnimationViewController; // Used to obtain the sensor location. @NonNull private FingerprintSensorPropertiesInternal mSensorProps; @@ -64,8 +57,6 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin private final float mSensorTouchAreaCoefficient; @Nullable private String mDebugMessage; private boolean mIlluminationRequested; - private int mStatusBarState; - private boolean mNotificationShadeExpanded; public UdfpsView(Context context, AttributeSet attrs) { super(context, attrs); @@ -108,15 +99,6 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin mSensorProps = properties; } - void setAnimationView(@NonNull UdfpsAnimationView animation) { - mAnimationView = animation; - animation.setParent(this); - - // TODO: Consider using a ViewStub placeholder to maintain positioning and inflating it - // after the animation type has been decided. - addView(animation, 0); - } - @Override public void setHbmCallback(@Nullable HbmCallback callback) { mHbmSurfaceView.setHbmCallback(callback); @@ -124,45 +106,38 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin @Override public void dozeTimeTick() { - if (mAnimationView == null) { - return; - } - mAnimationView.dozeTimeTick(); - } - - @Override - public void onStateChanged(int newState) { - mStatusBarState = newState; - } - - @Override - public void onExpansionChanged(float expansion, boolean expanded) { - mNotificationShadeExpanded = expanded; - - if (mAnimationView != null) { - mAnimationView.onExpansionChanged(expansion, expanded); + if (mAnimationViewController != null) { + mAnimationViewController.dozeTimeTick(); } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - mSensorRect.set(0 + mAnimationView.getPaddingX(), - 0 + mAnimationView.getPaddingY(), - 2 * mSensorProps.sensorRadius + mAnimationView.getPaddingX(), - 2 * mSensorProps.sensorRadius + mAnimationView.getPaddingY()); + int paddingX = mAnimationViewController == null ? 0 + : mAnimationViewController.getPaddingX(); + int paddingY = mAnimationViewController == null ? 0 + : mAnimationViewController.getPaddingY(); + mSensorRect.set( + paddingX, + paddingY, + 2 * mSensorProps.sensorRadius + paddingX, + 2 * mSensorProps.sensorRadius + paddingY); mHbmSurfaceView.onSensorRectUpdated(new RectF(mSensorRect)); - mAnimationView.onSensorRectUpdated(new RectF(mSensorRect)); + if (mAnimationViewController != null) { + mAnimationViewController.onSensorRectUpdated(new RectF(mSensorRect)); + } + } + + void setAnimationViewController(UdfpsAnimationViewController animationViewController) { + mAnimationViewController = animationViewController; } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); Log.v(TAG, "onAttachedToWindow"); - - // Retrieve the colors each time, since it depends on day/night mode - mAnimationView.updateColor(); } @Override @@ -188,7 +163,9 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin boolean isWithinSensorArea(float x, float y) { // The X and Y coordinates of the sensor's center. - final PointF translation = mAnimationView.getTouchTranslation(); + final PointF translation = mAnimationViewController == null + ? new PointF(0, 0) + : mAnimationViewController.getTouchTranslation(); final float cx = mSensorRect.centerX() + translation.x; final float cy = mSensorRect.centerY() + translation.y; // Radii along the X and Y axes. @@ -199,18 +176,7 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin && x < (cx + rx * mSensorTouchAreaCoefficient) && y > (cy - ry * mSensorTouchAreaCoefficient) && y < (cy + ry * mSensorTouchAreaCoefficient) - && !shouldPauseAuth(); - } - - /** - * States where UDFPS should temporarily not be authenticating. Instead of completely stopping - * authentication which would cause the UDFPS icons to abruptly disappear, do it here by not - * sending onFingerDown and smoothly animating away. - */ - boolean shouldPauseAuth() { - return (mNotificationShadeExpanded && mStatusBarState != KEYGUARD) - || mStatusBarState == SHADE_LOCKED - || mStatusBarState == FULLSCREEN_USER_SWITCHER; + && !mAnimationViewController.shouldPauseAuth(); } boolean isIlluminationRequested() { @@ -223,7 +189,9 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin @Override public void startIllumination(@Nullable Runnable onIlluminatedRunnable) { mIlluminationRequested = true; - mAnimationView.onIlluminationStarting(); + if (mAnimationViewController != null) { + mAnimationViewController.onIlluminationStarting(); + } mHbmSurfaceView.setVisibility(View.VISIBLE); mHbmSurfaceView.startIllumination(onIlluminatedRunnable); } @@ -231,7 +199,9 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin @Override public void stopIllumination() { mIlluminationRequested = false; - mAnimationView.onIlluminationStopped(); + if (mAnimationViewController != null) { + mAnimationViewController.onIlluminationStopped(); + } mHbmSurfaceView.setVisibility(View.INVISIBLE); mHbmSurfaceView.stopIllumination(); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java index 6572ca95b5c3..efb799294004 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java @@ -18,7 +18,6 @@ package com.android.systemui.classifier; import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_SUCCESS; import static com.android.systemui.classifier.FalsingModule.BRIGHT_LINE_GESTURE_CLASSIFERS; -import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_MS; import android.net.Uri; import android.os.Build; @@ -29,11 +28,9 @@ import androidx.annotation.NonNull; import com.android.internal.logging.MetricsLogger; import com.android.systemui.classifier.FalsingDataProvider.SessionListener; -import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.TestHarness; import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.sensors.ThresholdSensor; import java.io.FileDescriptor; @@ -63,14 +60,13 @@ public class BrightLineFalsingManager implements FalsingManager { private static final int RECENT_INFO_LOG_SIZE = 40; private static final int RECENT_SWIPE_LOG_SIZE = 20; + private static final double TAP_CONFIDENCE_THRESHOLD = 0.7; private final FalsingDataProvider mDataProvider; private final DockManager mDockManager; private final SingleTapClassifier mSingleTapClassifier; private final DoubleTapClassifier mDoubleTapClassifier; private final HistoryTracker mHistoryTracker; - private final DelayableExecutor mDelayableExecutor; - private final long mDoubleTapTimeMs; private final boolean mTestHarness; private final MetricsLogger mMetricsLogger; private int mIsFalseTouchCalls; @@ -98,19 +94,7 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void onGestureComplete(long completionTimeMs) { if (mPriorResults != null) { - // Single taps that may become double taps don't get added right away. - if (mClassifyAsSingleTap) { - Collection<FalsingClassifier.Result> singleTapResults = mPriorResults; - mSingleTapHistoryCanceller = mDelayableExecutor.executeDelayed( - () -> { - mSingleTapHistoryCanceller = null; - mHistoryTracker.addResults(singleTapResults, completionTimeMs); - }, - mDoubleTapTimeMs); - mClassifyAsSingleTap = false; // Don't treat things as single taps by default. - } else { - mHistoryTracker.addResults(mPriorResults, completionTimeMs); - } + mHistoryTracker.addResults(mPriorResults, completionTimeMs); mPriorResults = null; } else { // Gestures that were not classified get treated as a false. @@ -123,17 +107,13 @@ public class BrightLineFalsingManager implements FalsingManager { }; private Collection<FalsingClassifier.Result> mPriorResults; - private boolean mClassifyAsSingleTap; - private Runnable mSingleTapHistoryCanceller; @Inject public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider, DockManager dockManager, MetricsLogger metricsLogger, @Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers, SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier, - HistoryTracker historyTracker, @Main DelayableExecutor delayableExecutor, - @Named(DOUBLE_TAP_TIMEOUT_MS) long doubleTapTimeMs, - @TestHarness boolean testHarness) { + HistoryTracker historyTracker, @TestHarness boolean testHarness) { mDataProvider = falsingDataProvider; mDockManager = dockManager; mMetricsLogger = metricsLogger; @@ -141,8 +121,6 @@ public class BrightLineFalsingManager implements FalsingManager { mSingleTapClassifier = singleTapClassifier; mDoubleTapClassifier = doubleTapClassifier; mHistoryTracker = historyTracker; - mDelayableExecutor = delayableExecutor; - mDoubleTapTimeMs = doubleTapTimeMs; mTestHarness = testHarness; mDataProvider.addSessionListener(mSessionListener); @@ -158,7 +136,6 @@ public class BrightLineFalsingManager implements FalsingManager { public boolean isFalseTouch(@Classifier.InteractionType int interactionType) { boolean result; - mClassifyAsSingleTap = false; mDataProvider.setInteractionType(interactionType); if (!mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()) { @@ -166,7 +143,7 @@ public class BrightLineFalsingManager implements FalsingManager { mClassifiers.stream().map(falsingClassifier -> { FalsingClassifier.Result classifierResult = falsingClassifier.classifyGesture( - mHistoryTracker.falsePenalty(), + mHistoryTracker.falseBelief(), mHistoryTracker.falseConfidence()); if (classifierResult.isFalse()) { logInfo(String.format( @@ -217,9 +194,7 @@ public class BrightLineFalsingManager implements FalsingManager { } @Override - public boolean isFalseTap(boolean robustCheck) { - mClassifyAsSingleTap = true; - + public boolean isFalseTap(boolean robustCheck, double falsePenalty) { FalsingClassifier.Result singleTapResult = mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents()); mPriorResults = Collections.singleton(singleTapResult); @@ -233,14 +208,24 @@ public class BrightLineFalsingManager implements FalsingManager { return true; } - // TODO(b/172655679): More heuristics to come. For now, allow touches through if face-authed if (robustCheck) { - boolean result = !mDataProvider.isJustUnlockedWithFace(); - mPriorResults = Collections.singleton( - result ? FalsingClassifier.Result.falsed(0.1, "no face detected") - : FalsingClassifier.Result.passed(1)); - - return result; + if (mDataProvider.isJustUnlockedWithFace()) { + // Immediately pass if a face is detected. + mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1)); + return false; + } else if (!isFalseDoubleTap()) { + // We must check double tapping before other heuristics. This is because + // the double tap will fail if there's only been one tap. We don't want that + // failure to be recorded in mPriorResults. + return false; + } else if (mHistoryTracker.falseBelief() > TAP_CONFIDENCE_THRESHOLD) { + mPriorResults = Collections.singleton( + FalsingClassifier.Result.falsed(0, "bad history")); + return true; + } else { + mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(0.1)); + return false; + } } return false; @@ -248,7 +233,6 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public boolean isFalseDoubleTap() { - mClassifyAsSingleTap = false; FalsingClassifier.Result result = mDoubleTapClassifier.classifyGesture(); mPriorResults = Collections.singleton(result); if (result.isFalse()) { @@ -258,12 +242,6 @@ public class BrightLineFalsingManager implements FalsingManager { if (reason != null) { logInfo(reason); } - } else { - // A valid double tap prevents an invalid single tap from going into history. - if (mSingleTapHistoryCanceller != null) { - mSingleTapHistoryCanceller.run(); - mSingleTapHistoryCanceller = null; - } } return result.isFalse(); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java index bbb937176f59..ffcdb93b11b1 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java @@ -62,7 +62,7 @@ class DiagonalClassifier extends FalsingClassifier { VERTICAL_ANGLE_RANGE); } - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { float angle = getAngle(); if (angle == Float.MAX_VALUE) { // Unknown angle diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java index 4cb5aa2cce37..0f121c1c9ae7 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java @@ -147,7 +147,7 @@ class DistanceClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { return !getPassedFlingThreshold() ? Result.falsed(0.5, getReason()) : Result.passed(0.5); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java index 64576a97ddb2..baa54a65e4fc 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java @@ -22,7 +22,6 @@ import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TOUCH_SLO import android.view.MotionEvent; import java.util.List; -import java.util.Queue; import javax.inject.Inject; import javax.inject.Named; @@ -47,15 +46,14 @@ public class DoubleTapClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { List<MotionEvent> secondTapEvents = getRecentMotionEvents(); - Queue<? extends List<MotionEvent>> historicalEvents = getHistoricalEvents(); - List<MotionEvent> firstTapEvents = historicalEvents.peek(); + List<MotionEvent> firstTapEvents = getPriorMotionEvents(); StringBuilder reason = new StringBuilder(); if (firstTapEvents == null) { - return Result.falsed(1, "Only one gesture recorded"); + return Result.falsed(0, "Only one gesture recorded"); } return !isDoubleTap(firstTapEvents, secondTapEvents, reason) diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java index dbfeacfa91c4..1af5f7c488a5 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java @@ -21,7 +21,6 @@ import android.view.MotionEvent; import com.android.systemui.util.sensors.ProximitySensor; import java.util.List; -import java.util.Queue; /** * Base class for rules that determine False touches. @@ -40,8 +39,8 @@ public abstract class FalsingClassifier { return mDataProvider.getRecentMotionEvents(); } - Queue<? extends List<MotionEvent>> getHistoricalEvents() { - return mDataProvider.getHistoricalMotionEvents(); + List<MotionEvent> getPriorMotionEvents() { + return mDataProvider.getPriorMotionEvents(); } MotionEvent getFirstMotionEvent() { @@ -125,7 +124,7 @@ public abstract class FalsingClassifier { * See also {@link #classifyGesture(double, double)}. */ Result classifyGesture() { - return calculateFalsingResult(0, 0); + return calculateFalsingResult(0.5, 0); } /** @@ -136,16 +135,16 @@ public abstract class FalsingClassifier { * * See also {@link #classifyGesture()}. */ - Result classifyGesture(double historyPenalty, double historyConfidence) { - return calculateFalsingResult(historyPenalty, historyConfidence); + Result classifyGesture(double historyBelief, double historyConfidence) { + return calculateFalsingResult(historyBelief, historyConfidence); } /** * Calculate a result based on available data. * - * When passed a historyConfidence of 0, the history penalty should be wholly ignored. + * When passed a historyConfidence of 0, the history belief should be wholly ignored. */ - abstract Result calculateFalsingResult(double historyPenalty, double historyConfidence); + abstract Result calculateFalsingResult(double historyBelief, double historyConfidence); /** */ public static void logDebug(String msg) { @@ -165,7 +164,7 @@ public abstract class FalsingClassifier { /** * A Falsing result that encapsulates the boolean result along with confidence and a reason. */ - static class Result { + public static class Result { private final boolean mFalsed; private final double mConfidence; private final String mReason; @@ -194,14 +193,14 @@ public abstract class FalsingClassifier { /** * Construct a "falsed" result indicating that a gesture should be treated as accidental. */ - static Result falsed(double confidence, String reason) { + public static Result falsed(double confidence, String reason) { return new Result(true, confidence, reason); } /** * Construct a "passed" result indicating that a gesture should be allowed. */ - static Result passed(double confidence) { + public static Result passed(double confidence) { return new Result(false, confidence, null); } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java index b0bbab366e93..bb037202d985 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java @@ -120,5 +120,8 @@ public interface FalsingCollector { /** */ void cleanup(); + + /** */ + void updateFalseConfidence(FalsingClassifier.Result result); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java index 12a060439106..939b45a2b4a5 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java @@ -153,4 +153,8 @@ public class FalsingCollectorFake implements FalsingCollector { @Override public void cleanup() { } + + @Override + public void updateFalseConfidence(FalsingClassifier.Result result) { + } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java index e08b43b3521f..e090006cca4f 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java @@ -29,6 +29,9 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.sensors.ThresholdSensor; +import com.android.systemui.util.time.SystemClock; + +import java.util.Collections; import javax.inject.Inject; @@ -42,8 +45,10 @@ class FalsingCollectorImpl implements FalsingCollector { private final FalsingDataProvider mFalsingDataProvider; private final FalsingManager mFalsingManager; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final HistoryTracker mHistoryTracker; private final ProximitySensor mProximitySensor; private final StatusBarStateController mStatusBarStateController; + private final SystemClock mSystemClock; private int mState; private boolean mShowingAod; @@ -80,13 +85,16 @@ class FalsingCollectorImpl implements FalsingCollector { @Inject FalsingCollectorImpl(FalsingDataProvider falsingDataProvider, FalsingManager falsingManager, - KeyguardUpdateMonitor keyguardUpdateMonitor, - ProximitySensor proximitySensor, StatusBarStateController statusBarStateController) { + KeyguardUpdateMonitor keyguardUpdateMonitor, HistoryTracker historyTracker, + ProximitySensor proximitySensor, StatusBarStateController statusBarStateController, + SystemClock systemClock) { mFalsingDataProvider = falsingDataProvider; mFalsingManager = falsingManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mHistoryTracker = historyTracker; mProximitySensor = proximitySensor; mStatusBarStateController = statusBarStateController; + mSystemClock = systemClock; mProximitySensor.setTag(PROXIMITY_SENSOR_TAG); @@ -282,6 +290,11 @@ class FalsingCollectorImpl implements FalsingCollector { mStatusBarStateController.removeCallback(mStatusBarStateListener); } + @Override + public void updateFalseConfidence(FalsingClassifier.Result result) { + mHistoryTracker.addResults(Collections.singleton(result), mSystemClock.uptimeMillis()); + } + private void updateInteractionType(@Classifier.InteractionType int type) { logDebug("InteractionType: " + type); mFalsingDataProvider.setInteractionType(type); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java index 4bacc1598490..336f13f117d3 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java @@ -23,13 +23,9 @@ import android.view.MotionEvent.PointerProperties; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.util.time.SystemClock; import java.util.ArrayList; -import java.util.Deque; -import java.util.LinkedList; import java.util.List; -import java.util.Queue; import javax.inject.Inject; @@ -40,24 +36,23 @@ import javax.inject.Inject; public class FalsingDataProvider { private static final long MOTION_EVENT_AGE_MS = 1000; - private static final long EXTENDED_MOTION_EVENT_AGE_MS = 30 * 1000; private static final float THREE_HUNDRED_SIXTY_DEG = (float) (2 * Math.PI); private final int mWidthPixels; private final int mHeightPixels; private final BatteryController mBatteryController; - private final SystemClock mSystemClock; private final float mXdpi; private final float mYdpi; private final List<SessionListener> mSessionListeners = new ArrayList<>(); private final List<MotionEventListener> mMotionEventListeners = new ArrayList<>(); - private final List<GestureCompleteListener> mGestuerCompleteListeners = new ArrayList<>(); + private final List<GestureCompleteListener> mGestureCompleteListeners = new ArrayList<>(); private @Classifier.InteractionType int mInteractionType; - private final Deque<TimeLimitedMotionEventBuffer> mExtendedMotionEvents = new LinkedList<>(); private TimeLimitedMotionEventBuffer mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS); + private List<MotionEvent> mPriorMotionEvents; + private boolean mDirty = true; private float mAngle = 0; @@ -66,14 +61,12 @@ public class FalsingDataProvider { private boolean mJustUnlockedWithFace; @Inject - public FalsingDataProvider(DisplayMetrics displayMetrics, BatteryController batteryController, - SystemClock systemClock) { + public FalsingDataProvider(DisplayMetrics displayMetrics, BatteryController batteryController) { mXdpi = displayMetrics.xdpi; mYdpi = displayMetrics.ydpi; mWidthPixels = displayMetrics.widthPixels; mHeightPixels = displayMetrics.heightPixels; mBatteryController = batteryController; - mSystemClock = systemClock; FalsingClassifier.logInfo("xdpi, ydpi: " + getXdpi() + ", " + getYdpi()); FalsingClassifier.logInfo("width, height: " + getWidthPixels() + ", " + getHeightPixels()); @@ -111,10 +104,10 @@ public class FalsingDataProvider { private void completePriorGesture() { if (!mRecentMotionEvents.isEmpty()) { - mGestuerCompleteListeners.forEach(listener -> listener.onGestureComplete( + mGestureCompleteListeners.forEach(listener -> listener.onGestureComplete( mRecentMotionEvents.get(mRecentMotionEvents.size() - 1).getEventTime())); - mExtendedMotionEvents.addFirst(mRecentMotionEvents); + mPriorMotionEvents = mRecentMotionEvents; } } @@ -140,14 +133,8 @@ public class FalsingDataProvider { return mRecentMotionEvents; } - /** Returns recent gestures, exclusive of the most recent gesture. Newer gestures come first. */ - public Queue<? extends List<MotionEvent>> getHistoricalMotionEvents() { - long nowMs = mSystemClock.uptimeMillis(); - - mExtendedMotionEvents.removeIf( - motionEvents -> motionEvents.isFullyExpired(nowMs - EXTENDED_MOTION_EVENT_AGE_MS)); - - return mExtendedMotionEvents; + public List<MotionEvent> getPriorMotionEvents() { + return mPriorMotionEvents; } /** @@ -344,12 +331,12 @@ public class FalsingDataProvider { /** Register a {@link GestureCompleteListener}. */ public void addGestureCompleteListener(GestureCompleteListener listener) { - mGestuerCompleteListeners.add(listener); + mGestureCompleteListeners.add(listener); } /** Unregister a {@link GestureCompleteListener}. */ public void removeGestureCompleteListener(GestureCompleteListener listener) { - mGestuerCompleteListeners.remove(listener); + mGestureCompleteListeners.remove(listener); } void onSessionStarted() { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java index d4d8d06b081b..aac27cb43376 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java @@ -76,7 +76,7 @@ public class FalsingManagerFake implements FalsingManager { } @Override - public boolean isFalseTap(boolean robustCheck) { + public boolean isFalseTap(boolean robustCheck, double falsePenalty) { return robustCheck ? mIsFalseRobustTap : mIsFalseTap; } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index cbec0576e449..e9bb48c7b1a9 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -131,8 +131,8 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { } @Override - public boolean isFalseTap(boolean robustCheck) { - return mInternalFalsingManager.isFalseTap(robustCheck); + public boolean isFalseTap(boolean robustCheck, double falsePenalty) { + return mInternalFalsingManager.isFalseTap(robustCheck, falsePenalty); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java index 8bd94a122707..be48ec415652 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java @@ -36,12 +36,17 @@ import javax.inject.Inject; */ @SysUISingleton public class HistoryTracker { - private static final double HISTORY_DECAY = 0.8f; + private static final long HISTORY_MAX_AGE_MS = 10000; + // A score is decayed discretely every DECAY_INTERVAL_MS. private static final long DECAY_INTERVAL_MS = 100; - // We expire items once their decay factor is below 0.001. - private static final double MINIMUM_SCORE = 0.001; - private static final long TOTAL_DECAY_TIME_MS = - DECAY_INTERVAL_MS * (long) (Math.log(MINIMUM_SCORE) / Math.log(HISTORY_DECAY)); + // We expire items once their decay factor is below 0.1. + private static final double MINIMUM_SCORE = 0.1; + // This magic number is the factor a score is reduced by every DECAY_INTERVAL_MS. + // Once a score is HISTORY_MAX_AGE_MS ms old, it will be reduced by being multiplied by + // MINIMUM_SCORE. The math below ensures that. + private static final double HISTORY_DECAY = + Math.pow(10, Math.log10(MINIMUM_SCORE) / HISTORY_MAX_AGE_MS * DECAY_INTERVAL_MS); + private final SystemClock mSystemClock; DelayQueue<CombinedResult> mResults = new DelayQueue<>(); @@ -54,29 +59,36 @@ public class HistoryTracker { /** * Returns how much the HistoryClassifier thinks the past events indicate pocket dialing. * - * A result of 0 means that all prior gestures succeeded or there is no data to - * calculate a score with. Use {@link #falseConfidence()} to differentiate between the - * two cases. + * A result close to 0.5 means that prior data is inconclusive (inconsistent, lacking + * confidence, or simply lacking in quantity). + * + * A result close to 0 means that prior gestures indicate a success. * - * A result of 1 means that all prior gestures were very obviously false. The current gesture - * might be valid, but it should have a high-bar to be classified as such. + * A result close to 1 means that prior gestures were very obviously false. + * + * The current gesture might be different than what is reported by this method, but there should + * be a high-bar to be classified differently. * * See also {@link #falseConfidence()}. */ - double falsePenalty() { + double falseBelief() { //noinspection StatementWithEmptyBody while (mResults.poll() != null) { // Empty out the expired results. } if (mResults.isEmpty()) { - return 0; + return 0.5; } long nowMs = mSystemClock.uptimeMillis(); + // Get our Bayes on. return mResults.stream() .map(result -> result.getDecayedScore(nowMs)) - .reduce(0.0, Double::sum) / mResults.size(); + .reduce(0.5, + (prior, measurement) -> + (prior * measurement) + / (prior * measurement + (1 - prior) * (1 - measurement))); } /** @@ -91,7 +103,7 @@ public class HistoryTracker { * A result of 1 means that there are ample, fresh data to act upon that is all consistent * with each other. * - * See als {@link #falsePenalty()}. + * See als {@link #falseBelief()}. */ double falseConfidence() { //noinspection StatementWithEmptyBody @@ -126,6 +138,15 @@ public class HistoryTracker { finalScore /= results.size(); + // Never add a 0 or 1, else Bayes breaks down (a 0 and a 1 together results in NaN). In + // other words, you shouldn't need Bayes if you have 100% confidence one way or another. + // Instead, make the number ever so slightly smaller so that our math never breaks. + if (finalScore == 1) { + finalScore = 0.99999; + } else if (finalScore == 0) { + finalScore = 0.00001; + } + //noinspection StatementWithEmptyBody while (mResults.poll() != null) { // Empty out the expired results. @@ -147,15 +168,17 @@ public class HistoryTracker { private final double mScore; CombinedResult(long uptimeMillis, double score) { - mExpiryMs = uptimeMillis + TOTAL_DECAY_TIME_MS; + mExpiryMs = uptimeMillis + HISTORY_MAX_AGE_MS; mScore = score; } double getDecayedScore(long nowMs) { long remainingTimeMs = mExpiryMs - nowMs; - long decayedTimeMs = TOTAL_DECAY_TIME_MS - remainingTimeMs; + long decayedTimeMs = HISTORY_MAX_AGE_MS - remainingTimeMs; double timeIntervals = (double) decayedTimeMs / DECAY_INTERVAL_MS; - return mScore * Math.pow(HISTORY_DECAY, timeIntervals); + + // Score should decay towards 0.5. + return (mScore - 0.5) * Math.pow(HISTORY_DECAY, timeIntervals) + 0.5; } double getScore() { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java index cd399fe15de1..77d2d4267679 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java @@ -56,7 +56,7 @@ class PointerCountClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { int interactionType = getInteractionType(); int allowedPointerCount = (interactionType == QUICK_SETTINGS || interactionType == NOTIFICATION_DRAG_DOWN) diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java index 9ee85986c53c..6e97857f83da 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java @@ -112,7 +112,7 @@ class ProximityClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { if (getInteractionType() == QUICK_SETTINGS) { return Result.passed(0); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java index f2622ec4e6e9..4dd20ccff98e 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java @@ -39,12 +39,15 @@ public class SingleTapClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { return isTap(getRecentMotionEvents()); } /** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */ public Result isTap(List<MotionEvent> motionEvents) { + if (motionEvents.isEmpty()) { + return Result.falsed(0, "no motion events"); + } float downX = motionEvents.get(0).getX(); float downY = motionEvents.get(0).getY(); @@ -59,7 +62,7 @@ public class SingleTapClassifier extends FalsingClassifier { } else if (Math.abs(event.getY() - downY) >= mTouchSlop) { reason = "dY too big for a tap: " + Math.abs(event.getY() - downY) - + "vs " + + " vs " + mTouchSlop; return Result.falsed(0.5, reason); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java index 7969b4e83ac0..e5da38936593 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java @@ -42,18 +42,6 @@ public class TimeLimitedMotionEventBuffer implements List<MotionEvent> { mMotionEvents = new LinkedList<>(); } - /** - * Returns true if the most recent event in the buffer is past the expiration time. - * - * This method does not mutate the underlying data. This method does imply that, if the supplied - * expiration time is old enough and a new {@link MotionEvent} gets added to the buffer, all - * prior events would be removed. - */ - public boolean isFullyExpired(long expirationMs) { - return mMotionEvents.isEmpty() - || mMotionEvents.getLast().getEventTime() <= expirationMs; - } - private void ejectOldEvents() { if (mMotionEvents.isEmpty()) { return; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java index d470d6297170..4e032ea487c9 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java @@ -38,7 +38,7 @@ public class TypeClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { boolean vertical = isVertical(); boolean up = isUp(); boolean right = isRight(); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java index 2bfb2186191b..205825790461 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java @@ -84,7 +84,7 @@ class ZigZagClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { List<MotionEvent> motionEvents = getRecentMotionEvents(); // Rotate horizontal gestures to be horizontal between their first and last point. // Rotate vertical gestures to be vertical between their first and last point. diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt index fbdeb30d3911..ed625de9dce8 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt @@ -31,6 +31,7 @@ import com.android.systemui.controls.management.ControlsProviderSelectorActivity import com.android.systemui.controls.management.ControlsRequestDialog import com.android.systemui.controls.ui.ControlActionCoordinator import com.android.systemui.controls.ui.ControlActionCoordinatorImpl +import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.controls.ui.ControlsUiControllerImpl import com.android.systemui.dagger.SysUISingleton @@ -113,4 +114,9 @@ abstract class ControlsModule { abstract fun provideControlsRequestDialog( activity: ControlsRequestDialog ): Activity + + @Binds + @IntoMap + @ClassKey(ControlsActivity::class) + abstract fun provideControlsActivity(activity: ControlsActivity): Activity } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt index fc89783018bc..7dd1d28170b2 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt @@ -32,7 +32,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.controls.CustomIconCache import com.android.systemui.controls.controller.ControlsControllerImpl import com.android.systemui.controls.controller.StructureInfo -import com.android.systemui.controls.ui.ControlsDialog +import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.globalactions.GlobalActionsComponent import com.android.systemui.settings.CurrentUserTracker @@ -112,7 +112,11 @@ class ControlsEditingActivity @Inject constructor( if (backToGlobalActions) { globalActionsComponent.handleShowGlobalActionsMenu() } else { - ControlsDialog(applicationContext, broadcastDispatcher).show(uiController) + val i = Intent().apply { + component = ComponentName(applicationContext, ControlsActivity::class.java) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + } + startActivity(i) } animateExitAndFinish() } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt index 2d647a907b17..309901443393 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt @@ -40,7 +40,7 @@ import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.TooltipManager import com.android.systemui.controls.controller.ControlsControllerImpl import com.android.systemui.controls.controller.StructureInfo -import com.android.systemui.controls.ui.ControlsDialog +import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.globalactions.GlobalActionsComponent @@ -352,7 +352,11 @@ class ControlsFavoritingActivity @Inject constructor( if (backToGlobalActions) { globalActionsComponent.handleShowGlobalActionsMenu() } else { - ControlsDialog(applicationContext, broadcastDispatcher).show(uiController) + val i = Intent().apply { + component = ComponentName(applicationContext, ControlsActivity::class.java) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + } + startActivity(i) } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt index d5e41d031eac..fa1c41f01e6c 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt @@ -32,7 +32,7 @@ import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver import com.android.systemui.R import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.controls.controller.ControlsController -import com.android.systemui.controls.ui.ControlsDialog +import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main @@ -116,7 +116,11 @@ class ControlsProviderSelectorActivity @Inject constructor( if (backToGlobalActions) { globalActionsComponent.handleShowGlobalActionsMenu() } else { - ControlsDialog(applicationContext, broadcastDispatcher).show(uiController) + val i = Intent().apply { + component = ComponentName(applicationContext, ControlsActivity::class.java) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + } + startActivity(i) } animateExitAndFinish() } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt index d06568a7caf9..0db15e83fc93 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt @@ -16,6 +16,7 @@ package com.android.systemui.controls.ui +import android.content.Context import android.service.controls.Control /** @@ -24,8 +25,8 @@ import android.service.controls.Control */ interface ControlActionCoordinator { - // Handle actions launched from GlobalActionsDialog or ControlDialog - var startedFromGlobalActions: Boolean + // If launched from an Activity, continue within this stack + var activityContext: Context? /** * Close any dialogs which may have been open diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt index 6b300f4e07e4..58a5981845c7 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt @@ -18,6 +18,7 @@ package com.android.systemui.controls.ui import android.annotation.MainThread import android.app.Dialog +import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.pm.PackageManager @@ -60,7 +61,7 @@ class ControlActionCoordinatorImpl @Inject constructor( private var pendingAction: Action? = null private var actionsInProgress = mutableSetOf<String>() - override var startedFromGlobalActions: Boolean = true + override var activityContext: Context? = null companion object { private const val RESPONSE_TIMEOUT_IN_MILLIS = 3000L @@ -83,7 +84,7 @@ class ControlActionCoordinatorImpl @Inject constructor( bouncerOrRun(createAction(cvh.cws.ci.controlId, { cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK) if (cvh.usePanel()) { - showDialog(cvh, control.getAppIntent().getIntent()) + showDetail(cvh, control.getAppIntent().getIntent()) } else { cvh.action(CommandAction(templateId)) } @@ -109,7 +110,7 @@ class ControlActionCoordinatorImpl @Inject constructor( // Long press snould only be called when there is valid control state, otherwise ignore cvh.cws.control?.let { cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) - showDialog(cvh, it.getAppIntent().getIntent()) + showDetail(cvh, it.getAppIntent().getIntent()) } }, false /* blockable */)) } @@ -151,10 +152,16 @@ class ControlActionCoordinatorImpl @Inject constructor( activityStarter.dismissKeyguardThenExecute({ Log.d(ControlsUiController.TAG, "Device unlocked, invoking controls action") if (closeDialog) { - if (startedFromGlobalActions) { + activityContext?.let { + val i = Intent().apply { + component = ComponentName(context, ControlsActivity::class.java) + addFlags( + Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + putExtra(ControlsUiController.BACK_TO_GLOBAL_ACTIONS, false) + } + it.startActivity(i) + } ?: run { globalActionsComponent.handleShowGlobalActionsMenu() - } else { - ControlsDialog(context, broadcastDispatcher).show(lazyUiController.get()) } } else { action.invoke() @@ -170,9 +177,9 @@ class ControlActionCoordinatorImpl @Inject constructor( bgExecutor.execute { vibrator.vibrate(effect) } } - private fun showDialog(cvh: ControlViewHolder, intent: Intent) { + private fun showDetail(cvh: ControlViewHolder, intent: Intent) { bgExecutor.execute { - val activities: List<ResolveInfo> = cvh.context.packageManager.queryIntentActivities( + val activities: List<ResolveInfo> = context.packageManager.queryIntentActivities( intent, PackageManager.MATCH_DEFAULT_ONLY ) @@ -180,8 +187,8 @@ class ControlActionCoordinatorImpl @Inject constructor( uiExecutor.execute { // make sure the intent is valid before attempting to open the dialog if (activities.isNotEmpty() && taskViewFactory.isPresent) { - taskViewFactory.get().create(cvh.context, uiExecutor, { - dialog = DetailDialog(cvh, it, intent).also { + taskViewFactory.get().create(context, uiExecutor, { + dialog = DetailDialog(activityContext, it, intent, cvh).also { it.setOnDismissListener { _ -> dialog = null } it.show() } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt new file mode 100644 index 000000000000..a35b792ac7f1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.controls.ui + +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.view.WindowInsets +import android.view.WindowInsets.Type + +import com.android.systemui.R +import com.android.systemui.controls.management.ControlsAnimations +import com.android.systemui.util.LifecycleActivity +import javax.inject.Inject + +/** + * Displays Device Controls inside an activity + */ +class ControlsActivity @Inject constructor( + private val uiController: ControlsUiController +) : LifecycleActivity() { + + private lateinit var parent: ViewGroup + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(R.layout.controls_fullscreen) + + requireViewById<ViewGroup>(R.id.control_detail_root).apply { + setOnApplyWindowInsetsListener { + v: View, insets: WindowInsets -> + v.apply { + val l = getPaddingLeft() + val t = getPaddingTop() + val r = getPaddingRight() + setPadding(l, t, r, insets.getInsets(Type.systemBars()).bottom) + } + + WindowInsets.CONSUMED + } + } + } + + override fun onStart() { + super.onStart() + + parent = requireViewById<ViewGroup>(R.id.global_actions_controls) + parent.alpha = 0f + uiController.show(parent, { animateExitAndFinish() }, this) + } + + override fun onResume() { + super.onResume() + + ControlsAnimations.enterAnimation(parent).start() + } + + override fun onBackPressed() { + animateExitAndFinish() + } + + override fun onStop() { + super.onStop() + + uiController.hide() + } + + private fun animateExitAndFinish() { + ControlsAnimations.exitAnimation(parent, { finish() }).start() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialog.kt deleted file mode 100644 index 537334aeb2f7..000000000000 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialog.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.controls.ui - -import android.app.Dialog -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import android.view.View -import android.view.ViewGroup -import android.view.WindowManager - -import com.android.systemui.Interpolators -import com.android.systemui.R -import com.android.systemui.broadcast.BroadcastDispatcher -import javax.inject.Inject - -/** - * Show the controls space inside a dialog, as from the lock screen. - */ -class ControlsDialog @Inject constructor( - thisContext: Context, - val broadcastDispatcher: BroadcastDispatcher -) : Dialog(thisContext, R.style.Theme_SystemUI_Dialog_Control_LockScreen) { - - private val receiver = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - val action = intent.getAction() - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { - dismiss() - } - } - } - - init { - window.setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) - window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM - or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED) - - setContentView(R.layout.controls_in_dialog) - - requireViewById<ViewGroup>(R.id.control_detail_root).apply { - setOnClickListener { dismiss() } - (getParent() as View).setOnClickListener { dismiss() } - } - } - - fun show( - controller: ControlsUiController - ): ControlsDialog { - super.show() - - val vg = requireViewById<ViewGroup>(com.android.systemui.R.id.global_actions_controls) - vg.alpha = 0f - controller.show(vg, { dismiss() }, false /* startedFromGlobalActions */) - - vg.animate() - .alpha(1f) - .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN) - .setDuration(300) - - val filter = IntentFilter() - filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) - broadcastDispatcher.registerReceiver(receiver, filter) - - return this - } - - override fun dismiss() { - broadcastDispatcher.unregisterReceiver(receiver) - - if (!isShowing()) return - - super.dismiss() - } -} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt index 20bdf609357e..f86948ee8957 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt @@ -17,6 +17,7 @@ package com.android.systemui.controls.ui import android.content.ComponentName +import android.content.Context import android.service.controls.Control import android.service.controls.actions.ControlAction import android.view.ViewGroup @@ -30,7 +31,7 @@ interface ControlsUiController { public const val BACK_TO_GLOBAL_ACTIONS = "back_to_global_actions" } - fun show(parent: ViewGroup, onDismiss: Runnable, startedFromGlobalActions: Boolean) + fun show(parent: ViewGroup, onDismiss: Runnable, activityContext: Context?) fun hide() /** diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index c94d85aa58c4..0f7f48ff951a 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -148,7 +148,7 @@ class ControlsUiControllerImpl @Inject constructor ( override fun show( parent: ViewGroup, onDismiss: Runnable, - startedFromGlobalActions: Boolean + activityContext: Context? ) { Log.d(ControlsUiController.TAG, "show()") this.parent = parent @@ -156,7 +156,7 @@ class ControlsUiControllerImpl @Inject constructor ( hidden = false retainCache = false - controlActionCoordinator.startedFromGlobalActions = startedFromGlobalActions + controlActionCoordinator.activityContext = activityContext allStructures = controlsController.get().getFavorites() selectedStructure = loadPreference(allStructures) @@ -193,7 +193,7 @@ class ControlsUiControllerImpl @Inject constructor ( controlViewsById.clear() controlsById.clear() - show(parent, onDismiss, controlActionCoordinator.startedFromGlobalActions) + show(parent, onDismiss, controlActionCoordinator.activityContext) val showAnim = ObjectAnimator.ofFloat(parent, "alpha", 0.0f, 1.0f) showAnim.setInterpolator(DecelerateInterpolator(1.0f)) showAnim.setDuration(FADE_IN_MILLIS) @@ -268,7 +268,7 @@ class ControlsUiControllerImpl @Inject constructor ( intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true) intent.putExtra( ControlsUiController.BACK_TO_GLOBAL_ACTIONS, - controlActionCoordinator.startedFromGlobalActions + controlActionCoordinator.activityContext == null ) onDismiss.run() @@ -392,6 +392,17 @@ class ControlsUiControllerImpl @Inject constructor ( val inflater = LayoutInflater.from(context) inflater.inflate(R.layout.controls_with_favorites, parent, true) + if (controlActionCoordinator.activityContext == null) { + parent.requireViewById<View>(R.id.controls_spacer).apply { + visibility = View.VISIBLE + } + } else { + parent.requireViewById<ImageView>(R.id.controls_close).apply { + setOnClickListener { _: View -> onDismiss.run() } + visibility = View.VISIBLE + } + } + val maxColumns = findMaxColumns() val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup @@ -502,6 +513,8 @@ class ControlsUiControllerImpl @Inject constructor ( override fun hide() { hidden = true + controlActionCoordinator.activityContext = null + closeDialogs(true) controlsController.get().unsubscribe() diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt index 020694d89fce..9c788df362de 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt @@ -22,8 +22,8 @@ import android.app.ActivityTaskManager.INVALID_TASK_ID import android.app.Dialog import android.app.PendingIntent import android.content.ComponentName +import android.content.Context import android.content.Intent -import android.provider.Settings import android.view.View import android.view.ViewGroup import android.view.WindowInsets @@ -35,18 +35,20 @@ import com.android.systemui.R import com.android.wm.shell.TaskView /** - * A dialog that provides an {@link ActivityView}, allowing the application to provide + * A dialog that provides an {@link TaskView}, allowing the application to provide * additional information and actions pertaining to a {@link android.service.controls.Control}. * The activity being launched is specified by {@link android.service.controls.Control#getAppIntent}. */ class DetailDialog( - val cvh: ControlViewHolder, - val activityView: TaskView, - val intent: Intent -) : Dialog(cvh.context, R.style.Theme_SystemUI_Dialog_Control_DetailPanel) { - + val activityContext: Context?, + val taskView: TaskView, + val intent: Intent, + val cvh: ControlViewHolder +) : Dialog( + activityContext ?: cvh.context, + R.style.Theme_SystemUI_Dialog_Control_DetailPanel +) { companion object { - private const val PANEL_TOP_OFFSET = "systemui.controls_panel_top_offset" /* * Indicate to the activity that it is being rendered in a bottomsheet, and they * should optimize the layout for a smaller space. @@ -71,10 +73,19 @@ class DetailDialog( launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT) launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) - activityView.startActivity( - PendingIntent.getActivity(context, 0, launchIntent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE), - null, ActivityOptions.makeBasic()) + val options = activityContext?.let { + ActivityOptions.makeCustomAnimation( + it, + 0 /* enterResId */, + 0 /* exitResId */ + ) + } ?: ActivityOptions.makeBasic() + taskView.startActivity( + PendingIntent.getActivity(context, 0, launchIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE), + null, + options + ) } override fun onTaskRemovalStarted(taskId: Int) { @@ -92,7 +103,10 @@ class DetailDialog( } init { - window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) + if (activityContext == null) { + window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) + } + // To pass touches to the task inside TaskView. window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL) window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY) @@ -100,7 +114,7 @@ class DetailDialog( setContentView(R.layout.controls_detail_dialog) requireViewById<ViewGroup>(R.id.controls_activity_view).apply { - addView(activityView) + addView(taskView) } requireViewById<ImageView>(R.id.control_detail_close).apply { @@ -120,48 +134,34 @@ class DetailDialog( // consume all insets to achieve slide under effect window.getDecorView().setOnApplyWindowInsetsListener { - _: View, insets: WindowInsets -> - activityView.apply { + v: View, insets: WindowInsets -> + taskView.apply { val l = getPaddingLeft() val t = getPaddingTop() val r = getPaddingRight() setPadding(l, t, r, insets.getInsets(Type.systemBars()).bottom) } - WindowInsets.CONSUMED - } - - requireViewById<ViewGroup>(R.id.control_detail_root).apply { - // use flag only temporarily for testing - val resolver = cvh.context.contentResolver - val defaultOffsetInPx = cvh.context.resources - .getDimensionPixelSize(R.dimen.controls_activity_view_top_offset) - val offsetInPx = Settings.Secure.getInt(resolver, PANEL_TOP_OFFSET, defaultOffsetInPx) - - val lp = getLayoutParams() as ViewGroup.MarginLayoutParams - lp.topMargin = offsetInPx - setLayoutParams(lp) + val l = v.getPaddingLeft() + val b = v.getPaddingBottom() + val r = v.getPaddingRight() + v.setPadding(l, insets.getInsets(Type.systemBars()).top, r, b) - setOnClickListener { dismiss() } - (getParent() as View).setOnClickListener { dismiss() } + WindowInsets.CONSUMED } if (ScreenDecorationsUtils.supportsRoundedCornersOnWindows(context.getResources())) { val cornerRadius = context.resources .getDimensionPixelSize(R.dimen.controls_activity_view_corner_radius) - activityView.setCornerRadius(cornerRadius.toFloat()) + taskView.setCornerRadius(cornerRadius.toFloat()) } - } - - override fun show() { - activityView.setListener(cvh.uiExecutor, stateCallback) - super.show() + taskView.setListener(cvh.uiExecutor, stateCallback) } override fun dismiss() { if (!isShowing()) return - activityView.release() + taskView.release() super.dismiss() } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index c26cc4466c6d..d8ade2bdd21f 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -225,8 +225,8 @@ public class DozeLog implements Dumpable { * Appends wake-display event to the logs. * @param wake if we're waking up or sleeping. */ - public void traceWakeDisplay(boolean wake) { - mLogger.logWakeDisplay(wake); + public void traceWakeDisplay(boolean wake, @Reason int reason) { + mLogger.logWakeDisplay(wake, reason); } /** @@ -380,6 +380,7 @@ public class DozeLog implements Dumpable { case REASON_SENSOR_WAKE_UP: return "wakeup"; case REASON_SENSOR_TAP: return "tap"; case REASON_SENSOR_UDFPS_LONG_PRESS: return "udfps"; + case REASON_SENSOR_QUICK_PICKUP: return "quickPickup"; default: throw new IllegalArgumentException("invalid reason: " + pulseReason); } } @@ -389,7 +390,7 @@ public class DozeLog implements Dumpable { PULSE_REASON_SENSOR_SIGMOTION, REASON_SENSOR_PICKUP, REASON_SENSOR_DOUBLE_TAP, PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP, PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, REASON_SENSOR_TAP, - REASON_SENSOR_UDFPS_LONG_PRESS}) + REASON_SENSOR_UDFPS_LONG_PRESS, REASON_SENSOR_QUICK_PICKUP}) public @interface Reason {} public static final int PULSE_REASON_NONE = -1; public static final int PULSE_REASON_INTENT = 0; @@ -403,6 +404,7 @@ public class DozeLog implements Dumpable { public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8; public static final int REASON_SENSOR_TAP = 9; public static final int REASON_SENSOR_UDFPS_LONG_PRESS = 10; + public static final int REASON_SENSOR_QUICK_PICKUP = 11; - public static final int TOTAL_REASONS = 11; + public static final int TOTAL_REASONS = 12; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt index fddefae6f5b6..9bc74be9b9c3 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt @@ -16,6 +16,7 @@ package com.android.systemui.doze +import android.view.Display import com.android.systemui.doze.DozeLog.Reason import com.android.systemui.doze.DozeLog.reasonToString import com.android.systemui.log.LogBuffer @@ -161,17 +162,18 @@ class DozeLogger @Inject constructor( fun logDisplayStateChanged(displayState: Int) { buffer.log(TAG, INFO, { - int1 = displayState + str1 = Display.stateToString(displayState) }, { - "Display state changed to $int1" + "Display state changed to $str1" }) } - fun logWakeDisplay(isAwake: Boolean) { + fun logWakeDisplay(isAwake: Boolean, @Reason reason: Int) { buffer.log(TAG, DEBUG, { bool1 = isAwake + int1 = reason }, { - "Display wakefulness changed, isAwake=$bool1" + "Display wakefulness changed, isAwake=$bool1, reason=${reasonToString(int1)}" }) } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index c542e5b07d9b..52c9f164a16e 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -113,6 +113,8 @@ public class DozeSensors { mCallback = callback; mProximitySensor = proximitySensor; + boolean udfpsEnrolled = + authController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser()); boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT); mSensors = new TriggerSensor[] { new TriggerSensor( @@ -159,7 +161,7 @@ public class DozeSensors { findSensorWithType(config.udfpsLongPressSensorType()), "doze_pulse_on_auth", true /* settingDef */, - authController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser()), + udfpsEnrolled, DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS, true /* reports touch coordinates */, true /* touchscreen */, @@ -181,6 +183,15 @@ public class DozeSensors { false /* touchscreen */, mConfig.getWakeLockScreenDebounce(), dozeLog), + new TriggerSensor( + findSensorWithType(config.quickPickupSensorType()), + Settings.Secure.DOZE_QUICK_PICKUP_GESTURE, + false /* setting default */, + config.quickPickupSensorEnabled(KeyguardUpdateMonitor.getCurrentUser()) + && udfpsEnrolled, + DozeLog.REASON_SENSOR_QUICK_PICKUP, + false /* touchCoords */, + false /* touchscreen */, dozeLog), }; setProxListening(false); // Don't immediately start listening when we register. diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index c617f3d751d0..04b46705226f 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -42,10 +42,13 @@ 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.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; import com.android.systemui.doze.dagger.DozeScope; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.Assert; +import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.settings.SecureSettings; @@ -76,6 +79,7 @@ public class DozeTriggers implements DozeMachine.Part { * Assuming that the screen should start on. */ private static boolean sWakeDisplaySensorState = true; + private Runnable mQuickPickupDozeCancellable; private static final int PROXIMITY_TIMEOUT_DELAY_MS = 500; @@ -96,6 +100,8 @@ public class DozeTriggers implements DozeMachine.Part { private final ProximitySensor.ProximityCheck mProxCheck; private final BroadcastDispatcher mBroadcastDispatcher; private final AuthController mAuthController; + private final DelayableExecutor mMainExecutor; + private final DelayableExecutor mBgExecutor; private long mNotificationPulseTime; private boolean mPulsePending; @@ -135,7 +141,10 @@ public class DozeTriggers implements DozeMachine.Part { DOZING_UPDATE_SENSOR_TAP(441), @UiEvent(doc = "Dozing updated because on display auth was triggered from AOD.") - DOZING_UPDATE_AUTH_TRIGGERED(657); + DOZING_UPDATE_AUTH_TRIGGERED(657), + + @UiEvent(doc = "Dozing updated because quick pickup sensor woke up.") + DOZING_UPDATE_QUICK_PICKUP(708); private final int mId; @@ -160,6 +169,7 @@ public class DozeTriggers implements DozeMachine.Part { case 8: return DOZING_UPDATE_SENSOR_WAKE_LOCKSCREEN; case 9: return DOZING_UPDATE_SENSOR_TAP; case 10: return DOZING_UPDATE_AUTH_TRIGGERED; + case 11: return DOZING_UPDATE_QUICK_PICKUP; default: return null; } } @@ -172,7 +182,8 @@ public class DozeTriggers implements DozeMachine.Part { WakeLock wakeLock, DockManager dockManager, ProximitySensor proximitySensor, ProximitySensor.ProximityCheck proxCheck, DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher, - SecureSettings secureSettings, AuthController authController) { + SecureSettings secureSettings, AuthController authController, + @Main DelayableExecutor mainExecutor, @Background DelayableExecutor bgExecutor) { mContext = context; mDozeHost = dozeHost; mConfig = config; @@ -189,6 +200,8 @@ public class DozeTriggers implements DozeMachine.Part { mDozeLog = dozeLog; mBroadcastDispatcher = broadcastDispatcher; mAuthController = authController; + mMainExecutor = mainExecutor; + mBgExecutor = bgExecutor; } @Override @@ -262,18 +275,22 @@ public class DozeTriggers implements DozeMachine.Part { boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP; boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP; boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS; - boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP; - boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN; + boolean isWakeOnPresence = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP; + boolean isWakeOnReach = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN; boolean isUdfpsLongPress = pulseReason == DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS; - boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0; - - if (isWakeDisplay) { - onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState()); + boolean isQuickPickup = pulseReason == DozeLog.REASON_SENSOR_QUICK_PICKUP; + boolean isWakeDisplayEvent = isQuickPickup || ((isWakeOnPresence || isWakeOnReach) + && rawValues != null && rawValues.length > 0 && rawValues[0] != 0); + + if (isWakeOnPresence || isQuickPickup) { + onWakeScreen(isQuickPickup || isWakeDisplayEvent, + mMachine.isExecutingTransition() ? null : mMachine.getState(), + pulseReason); } else if (isLongPress) { requestPulse(pulseReason, true /* alreadyPerformedProxCheck */, null /* onPulseSuppressedListener */); - } else if (isWakeLockScreen) { - if (wakeEvent) { + } else if (isWakeOnReach) { + if (isWakeDisplayEvent) { requestPulse(pulseReason, true /* alreadyPerformedProxCheck */, null /* onPulseSuppressedListener */); } @@ -370,13 +387,17 @@ public class DozeTriggers implements DozeMachine.Part { * @param state The current state, or null if the state could not be determined due to enqueued * transitions. */ - private void onWakeScreen(boolean wake, @Nullable DozeMachine.State state) { - mDozeLog.traceWakeDisplay(wake); - sWakeDisplaySensorState = wake; + private void onWakeScreen(boolean wake, @Nullable DozeMachine.State state, int reason) { + mDozeLog.traceWakeDisplay(wake, reason); + final boolean isWakeOnPresence = reason == DozeLog.REASON_SENSOR_WAKE_UP; + final boolean isQuickPickup = reason == DozeLog.REASON_SENSOR_QUICK_PICKUP; + if (isWakeOnPresence) { + sWakeDisplaySensorState = wake; + } if (wake) { proximityCheckThenCall((result) -> { - if (result != null && result) { + if (result != null && result) { // In pocket, drop event. return; } @@ -385,26 +406,51 @@ public class DozeTriggers implements DozeMachine.Part { // Logs AOD open due to sensor wake up. mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) .setType(MetricsEvent.TYPE_OPEN) - .setSubtype(DozeLog.REASON_SENSOR_WAKE_UP)); + .setSubtype(reason)); + + if (isQuickPickup) { + // schedule runnable to go back to DOZE + onQuickPickup(); + } + } else if (state == DozeMachine.State.DOZE_AOD && isQuickPickup) { + // elongate time in DOZE_AOD, schedule new runnable to go back to DOZE + onQuickPickup(); } - }, true /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP); + }, isQuickPickup /* alreadyPerformedProxCheck */, reason); } else { boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED); boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING); + boolean pulse = (state == DozeMachine.State.DOZE_REQUEST_PULSE) + || (state == DozeMachine.State.DOZE_PULSING) + || (state == DozeMachine.State.DOZE_PULSING_BRIGHT); + boolean docked = (state == DozeMachine.State.DOZE_AOD_DOCKED); if (!pausing && !paused) { + if (isQuickPickup && (pulse || docked)) { + 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(DozeLog.REASON_SENSOR_WAKE_UP)); + .setSubtype(reason)); } } } + private void onQuickPickup() { + cancelQuickPickupDelayableDoze(); + mQuickPickupDozeCancellable = mMainExecutor.executeDelayed(() -> { + onWakeScreen(false, + mMachine.isExecutingTransition() ? null : mMachine.getState(), + DozeLog.REASON_SENSOR_QUICK_PICKUP); + }, mDozeParameters.getQuickPickupAodDuration()); + } + @Override public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) { switch (newState) { case INITIALIZED: + sWakeDisplaySensorState = true; mBroadcastReceiver.register(mBroadcastDispatcher); mDozeHost.addCallback(mHostCallback); mDockManager.addListener(mDockEventListener); @@ -417,7 +463,7 @@ public class DozeTriggers implements DozeMachine.Part { mWantSensors = true; mWantTouchScreenSensors = true; if (newState == DozeMachine.State.DOZE_AOD && !sWakeDisplaySensorState) { - onWakeScreen(false, newState); + onWakeScreen(false, newState, DozeLog.REASON_SENSOR_WAKE_UP); } break; case DOZE_AOD_PAUSED: @@ -437,6 +483,7 @@ public class DozeTriggers implements DozeMachine.Part { mDozeSensors.requestTemporaryDisable(); break; case FINISH: + cancelQuickPickupDelayableDoze(); mBroadcastReceiver.unregister(mBroadcastDispatcher); mDozeHost.removeCallback(mHostCallback); mDockManager.removeListener(mDockEventListener); @@ -460,6 +507,17 @@ public class DozeTriggers implements DozeMachine.Part { mDozeSensors.setListening(mWantSensors, mWantTouchScreenSensors); } + /** + * Cancels last scheduled Runnable that transitions to STATE_DOZE (blank screen) after + * going into STATE_AOD (AOD screen) from the quick pickup gesture. + */ + private void cancelQuickPickupDelayableDoze() { + if (mQuickPickupDozeCancellable != null) { + mQuickPickupDozeCancellable.run(); + mQuickPickupDozeCancellable = null; + } + } + private void checkTriggersAtInit() { if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR || mDozeHost.isBlockingDoze() diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index d85b10167697..461a7303c184 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -79,7 +79,6 @@ import android.transition.AutoTransition; import android.transition.TransitionManager; import android.transition.TransitionSet; import android.util.ArraySet; -import android.util.FeatureFlagUtils; import android.util.Log; import android.view.ContextThemeWrapper; import android.view.IWindowManager; @@ -114,7 +113,6 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.EmergencyAffordanceManager; -import com.android.internal.util.ScreenRecordHelper; import com.android.internal.util.ScreenshotHelper; import com.android.internal.view.RotationPolicy; import com.android.internal.widget.LockPatternUtils; @@ -242,7 +240,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final boolean mShowSilentToggle; private final EmergencyAffordanceManager mEmergencyAffordanceManager; private final ScreenshotHelper mScreenshotHelper; - private final ScreenRecordHelper mScreenRecordHelper; private final ActivityStarter mActivityStarter; private final SysuiColorExtractor mSysuiColorExtractor; private final IStatusBarService mStatusBarService; @@ -378,7 +375,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mEmergencyAffordanceManager = new EmergencyAffordanceManager(context); mScreenshotHelper = new ScreenshotHelper(context); - mScreenRecordHelper = new ScreenRecordHelper(context); mConfigurationController.addCallback(this); @@ -979,7 +975,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } @VisibleForTesting - class ScreenshotAction extends SinglePressAction implements LongPressAction { + class ScreenshotAction extends SinglePressAction { final String KEY_SYSTEM_NAV_2BUTTONS = "system_nav_2buttons"; public ScreenshotAction() { @@ -1024,18 +1020,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, return NAV_BAR_MODE_2BUTTON == mContext.getResources().getInteger( com.android.internal.R.integer.config_navBarInteractionMode); } - - - @Override - public boolean onLongPress() { - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SCREENRECORD_LONG_PRESS)) { - mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS); - mScreenRecordHelper.launchRecordPrompt(); - } else { - onPress(); - } - return true; - } } @VisibleForTesting @@ -2236,7 +2220,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private void showControls(ControlsUiController controller) { mControlsUiController = controller; mControlsUiController.show(mControlsView, this::dismissForControlsActivity, - true /* startedFromGlobalActions */); + null /* activityContext */); } private boolean isWalletViewAvailable() { @@ -2465,7 +2449,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, }); if (mControlsUiController != null) { mControlsUiController.show(mControlsView, this::dismissForControlsActivity, - true /* startedFromGlobalActions */); + null /* activityContext */); } mBackgroundDrawable.setAlpha(0); @@ -2641,7 +2625,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mGlobalActionsLayout.updateList(); if (mControlsUiController != null) { mControlsUiController.show(mControlsView, this::dismissForControlsActivity, - true /* startedFromGlobalActions */); + null /* activityContext */); } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java index 4491cc12a3cb..0bfd065c4b67 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -212,6 +212,14 @@ public class NavigationBarController implements Callbacks, createNavigationBar(display, null /* savedState */, null /* result */); } + @Override + public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) { + final NavigationBarView navigationBarView = getNavigationBarView(displayId); + if (navigationBarView != null) { + navigationBarView.setNavigationBarLumaSamplingEnabled(enable); + } + } + /** * Recreates the navigation bar for the given display. */ diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index 35d5ca949f85..148c6652e851 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -1397,4 +1397,12 @@ public class NavigationBarView extends FrameLayout implements private final Consumer<Rect> mPipListener = bounds -> post(() -> { mEdgeBackGestureHandler.setPipStashExclusionBounds(bounds); }); + + void setNavigationBarLumaSamplingEnabled(boolean enable) { + if (enable) { + mRegionSamplingHelper.start(mSamplingBounds); + } else { + mRegionSamplingHelper.stop(); + } + } } 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 088743cd0f94..9e3be69c414e 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -609,20 +609,21 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa if (mVocab != null) { app = mVocab.getOrDefault(mPackageName, -1); } - // Check if we are within the tightest bounds beyond which - // we would not need to run the ML model. - boolean withinRange = x < mMLEnableWidth + mLeftInset - || x >= (mDisplaySize.x - mMLEnableWidth - mRightInset); - if (!withinRange) { + + // Denotes whether we should proceed with the gesture. Even if it is false, we may want to + // log it assuming it is not invalid due to exclusion. + boolean withinRange = x < mEdgeWidthLeft + mLeftInset + || x >= (mDisplaySize.x - mEdgeWidthRight - mRightInset); + if (withinRange) { int results = -1; - if (mUseMLModel && (results = getBackGesturePredictionsCategory(x, y, app)) != -1) { - withinRange = results == 1; - } else { - // Denotes whether we should proceed with the gesture. - // Even if it is false, we may want to log it assuming - // it is not invalid due to exclusion. - withinRange = x < mEdgeWidthLeft + mLeftInset - || x >= (mDisplaySize.x - mEdgeWidthRight - mRightInset); + + // Check if we are within the tightest bounds beyond which we would not need to run the + // ML model + boolean withinMinRange = x < mMLEnableWidth + mLeftInset + || x >= (mDisplaySize.x - mMLEnableWidth - mRightInset); + if (!withinMinRange && mUseMLModel + && (results = getBackGesturePredictionsCategory(x, y, app)) != -1) { + withinRange = (results == 1); } } @@ -726,7 +727,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa mGestureLog.removeFirst(); } mGestureLog.addLast(String.format( - "Gesture [%d,alw=%B,%B, %B,%B,disp=%s,wl=%d,il=%d,wr=%d,ir=%d,excl=%s]", + "Gesture [%d,alw=%B,%B,%B,%B,disp=%s,wl=%d,il=%d,wr=%d,ir=%d,excl=%s]", System.currentTimeMillis(), mAllowGesture, mIsOnLeftEdge, mIsBackGestureAllowed, QuickStepContract.isBackGestureDisabled(mSysUiFlags), mDisplaySize, mEdgeWidthLeft, mLeftInset, mEdgeWidthRight, mRightInset, mExcludeRegion)); diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java index a69ec278be91..378e49deb699 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java @@ -35,6 +35,7 @@ import android.view.ViewGroup; import com.android.systemui.R; import com.android.systemui.people.widget.PeopleSpaceWidgetManager; +import com.android.systemui.people.widget.PeopleTileKey; import com.android.systemui.statusbar.notification.NotificationEntryManager; import java.util.List; @@ -117,7 +118,7 @@ public class PeopleSpaceActivity extends Activity { String pkg = tile.getPackageName(); String status = PeopleSpaceUtils.getLastInteractionString(mContext, - tile.getLastInteractionTimestamp(), true); + tile.getLastInteractionTimestamp()); tileView.setStatus(status); tileView.setName(tile.getUserName().toString()); @@ -138,7 +139,9 @@ public class PeopleSpaceActivity extends Activity { + mAppWidgetId); } } - mPeopleSpaceWidgetManager.addNewWidget(tile, mAppWidgetId); + PeopleTileKey key = new PeopleTileKey( + tile.getId(), tile.getUserHandle().getIdentifier(), tile.getPackageName()); + mPeopleSpaceWidgetManager.addNewWidget(mAppWidgetId, key); finishActivity(); } diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java index 502c95c47d03..aa45178b6439 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java @@ -52,9 +52,7 @@ import android.icu.text.MeasureFormat; import android.icu.util.Measure; import android.icu.util.MeasureUnit; import android.net.Uri; -import android.os.Bundle; import android.os.Parcelable; -import android.os.ServiceManager; import android.provider.ContactsContract; import android.provider.Settings; import android.service.notification.ConversationChannelWrapper; @@ -71,10 +69,11 @@ import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.util.ArrayUtils; import com.android.settingslib.utils.ThreadUtils; -import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.people.widget.AppWidgetOptionsHelper; import com.android.systemui.people.widget.LaunchConversationActivity; import com.android.systemui.people.widget.PeopleSpaceWidgetProvider; +import com.android.systemui.people.widget.PeopleTileKey; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -106,7 +105,6 @@ public class PeopleSpaceUtils { private static final int DAYS_IN_A_WEEK = 7; private static final int MIN_HOUR = 1; private static final int ONE_DAY = 1; - public static final String OPTIONS_PEOPLE_SPACE_TILE = "options_people_space_tile"; public static final String PACKAGE_NAME = "package_name"; public static final String USER_ID = "user_id"; public static final String SHORTCUT_ID = "shortcut_id"; @@ -115,6 +113,9 @@ public class PeopleSpaceUtils { public static final int INVALID_WIDGET_ID = -1; public static final int INVALID_USER_ID = -1; + public static final PeopleTileKey EMPTY_KEY = + new PeopleTileKey(EMPTY_STRING, INVALID_USER_ID, EMPTY_STRING); + private static final Pattern DOUBLE_EXCLAMATION_PATTERN = Pattern.compile("[!][!]+"); private static final Pattern DOUBLE_QUESTION_PATTERN = Pattern.compile("[?][?]+"); private static final Pattern ANY_DOUBLE_MARK_PATTERN = Pattern.compile("[!?][!?]+"); @@ -200,67 +201,76 @@ public class PeopleSpaceUtils { AppWidgetManager appWidgetManager, IPeopleManager peopleManager) { Map<Integer, PeopleSpaceTile> widgetIdToTile = new HashMap<>(); for (int appWidgetId : appWidgetIds) { - PeopleSpaceTile tile = getPeopleSpaceTile(peopleManager, appWidgetManager, context, - appWidgetId); + PeopleSpaceTile tile = getPeopleSpaceTile( + context, appWidgetId, appWidgetManager, peopleManager); if (tile == null) { if (DEBUG) Log.d(TAG, "Matching conversation not found for shortcut ID"); //TODO: Delete app widget id when crash is fixed (b/172932636) continue; } - - if (DEBUG) Log.d(TAG, "Widget: " + appWidgetId + ", " + tile.getUserName()); - RemoteViews views = createRemoteViews(context, tile, appWidgetId); - - // Tell the AppWidgetManager to perform an update on the current app widget. - appWidgetManager.updateAppWidget(appWidgetId, views); - + updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, tile); widgetIdToTile.put(appWidgetId, tile); } getBirthdaysOnBackgroundThread(context, appWidgetManager, widgetIdToTile, appWidgetIds); } + /** + * Returns a {@link PeopleSpaceTile} based on the {@code appWidgetId}. If the PeopleSpaceTile + * isn't cached, store it in AppWidgetOptions. + */ @Nullable - public static PeopleSpaceTile getPeopleSpaceTile(IPeopleManager peopleManager, - AppWidgetManager appWidgetManager, - Context context, int appWidgetId) { - try { - // Migrate storage for existing users. - SharedPreferences widgetSp = context.getSharedPreferences(String.valueOf(appWidgetId), - Context.MODE_PRIVATE); - String pkg = widgetSp.getString(PACKAGE_NAME, EMPTY_STRING); - int userId = widgetSp.getInt(USER_ID, INVALID_USER_ID); - String shortcutId = widgetSp.getString(SHORTCUT_ID, EMPTY_STRING); - if (!validKey(shortcutId, pkg, userId)) { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - shortcutId = sp.getString(String.valueOf(appWidgetId), null); - if (shortcutId == null) { - Log.e(TAG, "Cannot restore widget"); - return null; - } - migrateExistingUsersToNewStorage(context, shortcutId, appWidgetId); - pkg = widgetSp.getString(PACKAGE_NAME, EMPTY_STRING); - userId = widgetSp.getInt(USER_ID, INVALID_USER_ID); - } + public static PeopleSpaceTile getPeopleSpaceTile(Context context, int appWidgetId, + AppWidgetManager appWidgetManager, IPeopleManager peopleManager) { + // First, check if tile is cached in AppWidgetOptions. + PeopleSpaceTile tile = AppWidgetOptionsHelper.getPeopleTile(appWidgetManager, appWidgetId); + if (tile != null) { + if (DEBUG) Log.d(TAG, "People Tile is cached for widget: " + appWidgetId); + return tile; + } - // Check if tile is cached. - Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId); - PeopleSpaceTile tile = options.getParcelable(OPTIONS_PEOPLE_SPACE_TILE); - if (tile != null) { - return tile; - } + // If not, we get the PeopleTileKey from SharedPreferences, retrieve the Conversation from + // persisted storage, and cache it in AppWidgetOptions. + SharedPreferences widgetSp = context.getSharedPreferences( + String.valueOf(appWidgetId), + Context.MODE_PRIVATE); + PeopleTileKey sharedPreferencesKey = new PeopleTileKey( + widgetSp.getString(SHORTCUT_ID, EMPTY_STRING), + widgetSp.getInt(USER_ID, INVALID_USER_ID), + widgetSp.getString(PACKAGE_NAME, EMPTY_STRING)); - // If tile is null, we need to retrieve from persisted storage. - if (DEBUG) { - Log.d(TAG, - "Retrieving from storage after reboots: " + shortcutId + " user: " + userId - + " pkg: " + pkg); - } + if (!sharedPreferencesKey.isValid()) { + Log.e(TAG, "Cannot find shortcut info for widgetId: " + appWidgetId); + return null; + } + + if (DEBUG) Log.d(TAG, "PeopleTile key is present in sharedPreferences: " + appWidgetId); + // If tile is null, we need to retrieve from persisted storage. + return getPeopleTileFromPersistentStorage(context, sharedPreferencesKey, peopleManager); + } + + /** + * Returns a {@link PeopleSpaceTile} based on {@link ConversationChannel} returned by + * {@link IPeopleManager}. + */ + public static PeopleSpaceTile getPeopleTileFromPersistentStorage(Context context, + PeopleTileKey peopleTileKey, IPeopleManager peopleManager) { + try { + if (DEBUG) Log.d(TAG, "Retrieving Tile from storage: " + peopleTileKey.toString()); LauncherApps launcherApps = context.getSystemService(LauncherApps.class); - ConversationChannel channel = peopleManager.getConversation(pkg, userId, shortcutId); + if (launcherApps == null) { + Log.d(TAG, "LauncherApps is null"); + return null; + } + + ConversationChannel channel = peopleManager.getConversation( + peopleTileKey.getPackageName(), + peopleTileKey.getUserId(), + peopleTileKey.getShortcutId()); if (channel == null) { Log.d(TAG, "Could not retrieve conversation from storage"); return null; } + return new PeopleSpaceTile.Builder(channel, launcherApps).build(); } catch (Exception e) { Log.e(TAG, "Failed to retrieve conversation for tile: " + e); @@ -269,79 +279,46 @@ public class PeopleSpaceUtils { } /** Returns stored widgets for the conversation specified. */ - public static Set<String> getStoredWidgetIds(SharedPreferences sp, String shortcutId, - String packageName, int userId) { - if (shortcutId == null || packageName == null) { + public static Set<String> getStoredWidgetIds(SharedPreferences sp, PeopleTileKey key) { + if (!key.isValid()) { return new HashSet<>(); } - String key = PeopleSpaceUtils.getKey(shortcutId, packageName, userId); - return new HashSet<>(sp.getStringSet(key, new HashSet<>())); - } - - - /** Best-effort attempts to migrate existing users to the new storage format. */ - // TODO: Remove after sufficient time. Temporary migration storage for existing users. - private static void migrateExistingUsersToNewStorage(Context context, String shortcutId, - int appWidgetId) { - try { - List<PeopleSpaceTile> tiles = - PeopleSpaceUtils.getTiles(context, INotificationManager.Stub.asInterface( - ServiceManager.getService(Context.NOTIFICATION_SERVICE)), - IPeopleManager.Stub.asInterface( - ServiceManager.getService(Context.PEOPLE_SERVICE)), - context.getSystemService(LauncherApps.class), - Dependency.get(NotificationEntryManager.class)); - Optional<PeopleSpaceTile> entry = tiles.stream().filter( - e -> e.getId().equals(shortcutId)).findFirst(); - if (entry.isPresent()) { - if (DEBUG) Log.d(TAG, "Migrate storage for " + entry.get().getUserName()); - setStorageForTile(context, entry.get(), appWidgetId); - } else { - Log.e(TAG, "Could not migrate user. Delete old storage"); - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - SharedPreferences.Editor editor = sp.edit(); - editor.remove(String.valueOf(appWidgetId)); - editor.apply(); - } - } catch (Exception e) { - Log.e(TAG, "Could not query conversations"); - } + return new HashSet<>(sp.getStringSet(key.toString(), new HashSet<>())); } /** Sets all relevant storage for {@code appWidgetId} association to {@code tile}. */ - public static void setStorageForTile(Context context, PeopleSpaceTile tile, int appWidgetId) { + public static void setSharedPreferencesStorageForTile(Context context, PeopleTileKey key, + int appWidgetId) { // Write relevant persisted storage. SharedPreferences widgetSp = context.getSharedPreferences(String.valueOf(appWidgetId), Context.MODE_PRIVATE); SharedPreferences.Editor widgetEditor = widgetSp.edit(); - widgetEditor.putString(PeopleSpaceUtils.PACKAGE_NAME, tile.getPackageName()); - widgetEditor.putString(PeopleSpaceUtils.SHORTCUT_ID, tile.getId()); - int userId = getUserId(tile); - widgetEditor.putInt(PeopleSpaceUtils.USER_ID, userId); + widgetEditor.putString(PeopleSpaceUtils.PACKAGE_NAME, key.getPackageName()); + widgetEditor.putString(PeopleSpaceUtils.SHORTCUT_ID, key.getShortcutId()); + widgetEditor.putInt(PeopleSpaceUtils.USER_ID, key.getUserId()); widgetEditor.apply(); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences.Editor editor = sp.edit(); - editor.putString(String.valueOf(appWidgetId), tile.getId()); - String key = PeopleSpaceUtils.getKey(tile.getId(), tile.getPackageName(), userId); + editor.putString(String.valueOf(appWidgetId), key.getShortcutId()); + // Don't overwrite existing widgets with the same key. - Set<String> storedWidgetIds = new HashSet<>(sp.getStringSet(key, new HashSet<>())); + Set<String> storedWidgetIds = new HashSet<>( + sp.getStringSet(key.toString(), new HashSet<>())); storedWidgetIds.add(String.valueOf(appWidgetId)); - editor.putStringSet(key, storedWidgetIds); + editor.putStringSet(key.toString(), storedWidgetIds); editor.apply(); - - // Write cached storage. - updateAppWidgetOptionsAndView(AppWidgetManager.getInstance(context), context, appWidgetId, - tile); } /** Removes stored data when tile is deleted. */ - public static void removeStorageForTile(Context context, String key, int widgetId) { + public static void removeSharedPreferencesStorageForTile(Context context, PeopleTileKey key, + int widgetId) { // Delete widgetId mapping to key. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences.Editor editor = sp.edit(); - Set<String> storedWidgetIds = new HashSet<>(sp.getStringSet(key, new HashSet<>())); + Set<String> storedWidgetIds = new HashSet<>( + sp.getStringSet(key.toString(), new HashSet<>())); storedWidgetIds.remove(String.valueOf(widgetId)); - editor.putStringSet(key, storedWidgetIds); + editor.putStringSet(key.toString(), storedWidgetIds); editor.remove(String.valueOf(widgetId)); editor.apply(); @@ -361,12 +338,12 @@ public class PeopleSpaceUtils { Log.w(TAG, "NotificationEntryManager is null"); return tiles; } - Map<String, NotificationEntry> visibleNotifications = notificationEntryManager + Map<PeopleTileKey, NotificationEntry> visibleNotifications = notificationEntryManager .getVisibleNotifications() .stream() .filter(entry -> entry.getRanking() != null && entry.getRanking().getConversationShortcutInfo() != null) - .collect(Collectors.toMap(PeopleSpaceUtils::getKey, e -> e)); + .collect(Collectors.toMap(PeopleTileKey::new, e -> e)); if (DEBUG) { Log.d(TAG, "Number of visible notifications:" + visibleNotifications.size()); } @@ -378,16 +355,15 @@ public class PeopleSpaceUtils { } static PeopleSpaceTile augmentTileFromVisibleNotifications(Context context, - PeopleSpaceTile tile, Map<String, NotificationEntry> visibleNotifications) { - String shortcutId = tile.getId(); - String packageName = tile.getPackageName(); - int userId = getUserId(tile); - String key = getKey(shortcutId, packageName, userId); + PeopleSpaceTile tile, Map<PeopleTileKey, NotificationEntry> visibleNotifications) { + PeopleTileKey key = new PeopleTileKey( + tile.getId(), getUserId(tile), tile.getPackageName()); + if (!visibleNotifications.containsKey(key)) { - if (DEBUG) Log.d(TAG, "No existing notifications for key:" + key); + if (DEBUG) Log.d(TAG, "No existing notifications for key:" + key.toString()); return tile; } - if (DEBUG) Log.d(TAG, "Augmenting tile from visible notifications, key:" + key); + if (DEBUG) Log.d(TAG, "Augmenting tile from visible notifications, key:" + key.toString()); return augmentTileFromNotification(context, tile, visibleNotifications.get(key).getSbn()); } @@ -423,17 +399,6 @@ public class PeopleSpaceUtils { .build(); } - private static void updateAppWidgetOptions(AppWidgetManager appWidgetManager, int appWidgetId, - PeopleSpaceTile tile) { - if (tile == null) { - if (DEBUG) Log.d(TAG, "Requested to store null tile"); - return; - } - Bundle newOptions = new Bundle(); - newOptions.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, tile); - appWidgetManager.updateAppWidgetOptions(appWidgetId, newOptions); - } - /** Creates a {@link RemoteViews} for {@code tile}. */ public static RemoteViews createRemoteViews(Context context, PeopleSpaceTile tile, int appWidgetId) { @@ -653,7 +618,7 @@ public class PeopleSpaceUtils { } // TODO: Set subtext as Group Sender name once storing the name in PeopleSpaceTile. views.setTextViewText(R.id.subtext, PeopleSpaceUtils.getLastInteractionString( - context, tile.getLastInteractionTimestamp(), false)); + context, tile.getLastInteractionTimestamp())); return views; } @@ -662,7 +627,7 @@ public class PeopleSpaceUtils { RemoteViews views = new RemoteViews( context.getPackageName(), R.layout.people_space_large_avatar_tile); String status = PeopleSpaceUtils.getLastInteractionString( - context, tile.getLastInteractionTimestamp(), true); + context, tile.getLastInteractionTimestamp()); views.setTextViewText(R.id.last_interaction, status); return views; } @@ -808,8 +773,7 @@ public class PeopleSpaceUtils { } /** Returns a readable status describing the {@code lastInteraction}. */ - public static String getLastInteractionString(Context context, long lastInteraction, - boolean includeLastChatted) { + public static String getLastInteractionString(Context context, long lastInteraction) { if (lastInteraction == 0L) { Log.e(TAG, "Could not get valid last interaction"); return context.getString(R.string.basic_status); @@ -818,41 +782,20 @@ public class PeopleSpaceUtils { Duration durationSinceLastInteraction = Duration.ofMillis(now - lastInteraction); MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE); - MeasureFormat shortFormatter = MeasureFormat.getInstance(Locale.getDefault(), - MeasureFormat.FormatWidth.SHORT); if (durationSinceLastInteraction.toHours() < MIN_HOUR) { - if (includeLastChatted) { - return context.getString(R.string.last_interaction_status_less_than, - formatter.formatMeasures(new Measure(MIN_HOUR, MeasureUnit.HOUR))); - } - return context.getString(R.string.timestamp, shortFormatter.formatMeasures( + return context.getString(R.string.timestamp, formatter.formatMeasures( new Measure(durationSinceLastInteraction.toMinutes(), MeasureUnit.MINUTE))); } else if (durationSinceLastInteraction.toDays() < ONE_DAY) { - if (includeLastChatted) { - return context.getString(R.string.last_interaction_status, - formatter.formatMeasures( - new Measure(durationSinceLastInteraction.toHours(), - MeasureUnit.HOUR))); - } - return context.getString(R.string.timestamp, shortFormatter.formatMeasures( + return context.getString(R.string.timestamp, formatter.formatMeasures( new Measure(durationSinceLastInteraction.toHours(), MeasureUnit.HOUR))); } else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK) { - if (includeLastChatted) { - return context.getString(R.string.last_interaction_status, - formatter.formatMeasures( - new Measure(durationSinceLastInteraction.toDays(), - MeasureUnit.DAY))); - } - return context.getString(R.string.timestamp, shortFormatter.formatMeasures( + return context.getString(R.string.timestamp, formatter.formatMeasures( new Measure(durationSinceLastInteraction.toHours(), MeasureUnit.DAY))); } else { return context.getString(durationSinceLastInteraction.toDays() == DAYS_IN_A_WEEK - ? (includeLastChatted ? R.string.last_interaction_status : - R.string.timestamp) : - (includeLastChatted ? R.string.last_interaction_status_over - : R.string.over_timestamp), + ? R.string.timestamp : R.string.over_timestamp, formatter.formatMeasures( new Measure(durationSinceLastInteraction.toDays() / DAYS_IN_A_WEEK, MeasureUnit.WEEK))); @@ -957,11 +900,15 @@ public class PeopleSpaceUtils { removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId); } - /** Update app widget options and the current view. */ + /** Updates tile in app widget options and the current view. */ public static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager, Context context, int appWidgetId, PeopleSpaceTile tile) { - updateAppWidgetOptions(appWidgetManager, appWidgetId, tile); + AppWidgetOptionsHelper.setPeopleTile(appWidgetManager, appWidgetId, tile); + + if (DEBUG) Log.d(TAG, "Widget: " + appWidgetId + ", " + tile.getUserName()); RemoteViews views = createRemoteViews(context, tile, appWidgetId); + + // Tell the AppWidgetManager to perform an update on the current app widget. appWidgetManager.updateAppWidget(appWidgetId, views); } @@ -1006,44 +953,6 @@ public class PeopleSpaceUtils { return lookupKeysWithBirthdaysToday; } - static String getKey(NotificationEntry entry) { - if (entry.getRanking() == null || entry.getRanking().getConversationShortcutInfo() == null - || entry.getSbn() == null || entry.getSbn().getUser() == null) { - return null; - } - return getKey(entry.getRanking().getConversationShortcutInfo().getId(), - entry.getSbn().getPackageName(), - entry.getSbn().getUser().getIdentifier()); - } - - /** - * Returns the uniquely identifying key for the conversation. - * - * <p>{@code userId} will always be a number, so we put user ID as the - * delimiter between the app-provided strings of shortcut ID and package name. - * - * <p>There aren't restrictions on shortcut ID characters, but there are restrictions requiring - * a {@code packageName} to always start with a letter. This restriction means we are - * guaranteed to avoid cases like "a/b/0/0/package.name" having two potential keys, as the first - * case is impossible given the package name restrictions: - * <ul> - * <li>"a/b" + "/" + 0 + "/" + "0/packageName"</li> - * <li>"a/b/0" + "/" + 0 + "/" + "packageName"</li> - * </ul> - */ - @Nullable - public static String getKey(String shortcutId, String packageName, int userId) { - if (!validKey(shortcutId, packageName, userId)) { - return null; - } - return shortcutId + "/" + userId + "/" + packageName; - } - - /** Returns whether the key is valid. */ - public static boolean validKey(String shortcutId, String packageName, int userId) { - return !TextUtils.isEmpty(shortcutId) && !TextUtils.isEmpty(packageName) && userId >= 0; - } - /** Returns the userId associated with a {@link PeopleSpaceTile} */ public static int getUserId(PeopleSpaceTile tile) { return tile.getUserHandle().getIdentifier(); diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java b/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java new file mode 100644 index 000000000000..df08ee4a42bf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java @@ -0,0 +1,91 @@ +/* + * 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.people.widget; + +import static com.android.systemui.people.PeopleSpaceUtils.DEBUG; +import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_KEY; +import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_STRING; +import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID; +import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME; +import static com.android.systemui.people.PeopleSpaceUtils.SHORTCUT_ID; +import static com.android.systemui.people.PeopleSpaceUtils.USER_ID; + +import android.app.people.PeopleSpaceTile; +import android.appwidget.AppWidgetManager; +import android.os.Bundle; +import android.util.Log; + +/** Helper class encapsulating AppWidgetOptions for People Tile. */ +public class AppWidgetOptionsHelper { + private static final String TAG = "AppWidgetOptionsHelper"; + + /** Key to store {@link PeopleSpaceTile} in AppWidgetOptions Bundle. */ + public static final String OPTIONS_PEOPLE_TILE = "options_people_tile"; + + /** Sets {@link PeopleSpaceTile} in AppWidgetOptions. */ + public static void setPeopleTile(AppWidgetManager appWidgetManager, int appWidgetId, + PeopleSpaceTile tile) { + if (tile == null) { + if (DEBUG) Log.d(TAG, "Requested to store null tile"); + return; + } + Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId); + options.putParcelable(OPTIONS_PEOPLE_TILE, tile); + appWidgetManager.updateAppWidgetOptions(appWidgetId, options); + } + + /** Gets {@link PeopleSpaceTile} from AppWidgetOptions. */ + public static PeopleSpaceTile getPeopleTile(AppWidgetManager appWidgetManager, + int appWidgetId) { + Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId); + return options != null ? options.getParcelable(OPTIONS_PEOPLE_TILE) : null; + } + + /** Sets {@link PeopleTileKey} in AppWidgetOptions. */ + public static void setPeopleTileKey(AppWidgetManager appWidgetManager, int appWidgetId, + PeopleTileKey key) { + Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId); + options.putString(SHORTCUT_ID, key.getShortcutId()); + options.putInt(USER_ID, key.getUserId()); + options.putString(PACKAGE_NAME, key.getPackageName()); + appWidgetManager.updateAppWidgetOptions(appWidgetId, options); + } + + /** Gets {@link PeopleTileKey} from AppWidgetOptions. */ + public static PeopleTileKey getPeopleTileKey(AppWidgetManager appWidgetManager, + int appWidgetId) { + Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId); + if (options == null) { + return EMPTY_KEY; + } + return getPeopleTileKeyFromBundle(options); + } + + /** Gets {@link PeopleTileKey} from Bundle {@code options}. */ + public static PeopleTileKey getPeopleTileKeyFromBundle(Bundle options) { + String pkg = options.getString(PACKAGE_NAME, EMPTY_STRING); + int userId = options.getInt(USER_ID, INVALID_USER_ID); + String shortcutId = options.getString(SHORTCUT_ID, EMPTY_STRING); + return new PeopleTileKey(shortcutId, userId, pkg); + } + + /** Removes {@link PeopleTileKey} from AppWidgetOptions. */ + public static void removePeopleTileKey(AppWidgetManager appWidgetManager, + int appWidgetId) { + setPeopleTileKey(appWidgetManager, appWidgetId, EMPTY_KEY); + } +} 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 22ee9e89d0a0..7da9a80ca287 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java @@ -16,6 +16,7 @@ package com.android.systemui.people.widget; +import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_STRING; import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID; import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME; import static com.android.systemui.people.PeopleSpaceUtils.SHORTCUT_ID; @@ -38,6 +39,7 @@ import android.content.SharedPreferences; import android.content.pm.LauncherApps; import android.content.pm.ShortcutInfo; import android.net.Uri; +import android.os.Bundle; import android.os.ServiceManager; import android.os.UserHandle; import android.preference.PreferenceManager; @@ -78,8 +80,8 @@ public class PeopleSpaceWidgetManager { private PeopleManager mPeopleManager; public UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); @GuardedBy("mLock") - public static Map<String, PeopleSpaceWidgetProvider.TileConversationListener> mListeners = - new HashMap<>(); + public static Map<PeopleTileKey, PeopleSpaceWidgetProvider.TileConversationListener> + mListeners = new HashMap<>(); @Inject public PeopleSpaceWidgetManager(Context context) { @@ -122,8 +124,8 @@ public class PeopleSpaceWidgetManager { Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0; if (showSingleConversation) { synchronized (mLock) { - PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds, - mAppWidgetManager, mIPeopleManager); + PeopleSpaceUtils.updateSingleConversationWidgets( + mContext, widgetIds, mAppWidgetManager, mIPeopleManager); } } } catch (Exception e) { @@ -157,9 +159,11 @@ public class PeopleSpaceWidgetManager { return; } synchronized (mLock) { - Set<String> storedWidgetIds = getStoredWidgetIds(mSharedPrefs, sbnShortcutId, - sbn.getPackageName(), - UserHandle.getUserHandleForUid(sbn.getUid()).getIdentifier()); + PeopleTileKey key = new PeopleTileKey( + sbnShortcutId, + UserHandle.getUserHandleForUid(sbn.getUid()).getIdentifier(), + sbn.getPackageName()); + Set<String> storedWidgetIds = getStoredWidgetIds(mSharedPrefs, key); for (String widgetIdString : storedWidgetIds) { int widgetId = Integer.parseInt(widgetIdString); if (DEBUG) Log.d(TAG, "Storing notification change, key:" + sbn.getKey()); @@ -177,9 +181,9 @@ public class PeopleSpaceWidgetManager { public void updateWidgetsWithConversationChanged(ConversationChannel conversation) { ShortcutInfo info = conversation.getShortcutInfo(); synchronized (mLock) { - Set<String> storedWidgetIds = getStoredWidgetIds(mSharedPrefs, info.getId(), - info.getPackage(), - info.getUserId()); + PeopleTileKey key = new PeopleTileKey( + info.getId(), info.getUserId(), info.getPackage()); + Set<String> storedWidgetIds = getStoredWidgetIds(mSharedPrefs, key); for (String widgetIdString : storedWidgetIds) { if (DEBUG) { Log.d(TAG, @@ -197,9 +201,8 @@ public class PeopleSpaceWidgetManager { */ private void updateStorageAndViewWithConversationData(ConversationChannel conversation, int appWidgetId) { - PeopleSpaceTile storedTile = getPeopleSpaceTile(mIPeopleManager, mAppWidgetManager, - mContext, - appWidgetId); + PeopleSpaceTile storedTile = getPeopleSpaceTile( + mContext, appWidgetId, mAppWidgetManager, mIPeopleManager); if (storedTile == null) { if (DEBUG) Log.d(TAG, "Could not find stored tile to add conversation to"); return; @@ -232,9 +235,8 @@ public class PeopleSpaceWidgetManager { StatusBarNotification sbn, PeopleSpaceUtils.NotificationAction notificationAction, int appWidgetId) { - PeopleSpaceTile storedTile = getPeopleSpaceTile(mIPeopleManager, mAppWidgetManager, - mContext, - appWidgetId); + PeopleSpaceTile storedTile = getPeopleSpaceTile( + mContext, appWidgetId, mAppWidgetManager, mIPeopleManager); if (storedTile == null) { if (DEBUG) Log.d(TAG, "Could not find stored tile to add notification to"); return; @@ -312,18 +314,39 @@ public class PeopleSpaceWidgetManager { } }; - /** Adds {@code tile} mapped to {@code appWidgetId}. */ - public void addNewWidget(PeopleSpaceTile tile, int appWidgetId) { + /** + * Checks if this widget has been added externally, and this the first time we are learning + * about the widget. If so, the widget adder should have populated options with PeopleTileKey + * arguments. + */ + public void onAppWidgetOptionsChanged(int appWidgetId, Bundle newOptions) { + // Check if this widget has been added externally, and this the first time we are + // learning about the widget. If so, the widget adder should have populated options with + // PeopleTileKey arguments. + if (DEBUG) Log.d(TAG, "onAppWidgetOptionsChanged called for widget: " + appWidgetId); + PeopleTileKey optionsKey = AppWidgetOptionsHelper.getPeopleTileKeyFromBundle(newOptions); + if (optionsKey.isValid()) { + if (DEBUG) { + Log.d(TAG, "PeopleTileKey was present in Options, shortcutId: " + + optionsKey.getShortcutId()); + } + addNewWidget(appWidgetId, optionsKey); + AppWidgetOptionsHelper.removePeopleTileKey(mAppWidgetManager, appWidgetId); + } + } + + /** Adds{@code tile} mapped to {@code appWidgetId}. */ + public void addNewWidget(int appWidgetId, PeopleTileKey key) { mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_ADDED); synchronized (mLock) { - if (DEBUG) Log.d(TAG, "Add storage for : " + tile.getUserName()); - PeopleSpaceUtils.setStorageForTile(mContext, tile, appWidgetId); + if (DEBUG) Log.d(TAG, "Add storage for : " + key.getShortcutId()); + PeopleSpaceUtils.setSharedPreferencesStorageForTile(mContext, key, appWidgetId); } try { - if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + tile.getId()); - mLauncherApps.cacheShortcuts(tile.getPackageName(), - Collections.singletonList(tile.getId()), - tile.getUserHandle(), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS); + if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + key.getShortcutId()); + mLauncherApps.cacheShortcuts(key.getPackageName(), + Collections.singletonList(key.getShortcutId()), + UserHandle.of(key.getUserId()), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS); } catch (Exception e) { Log.w(TAG, "Exception caching shortcut:" + e); } @@ -335,19 +358,16 @@ public class PeopleSpaceWidgetManager { public void registerConversationListenerIfNeeded(int widgetId, PeopleSpaceWidgetProvider.TileConversationListener newListener) { // Retrieve storage needed for registration. - String packageName; - String shortcutId; - int userId; - String key; + PeopleTileKey key; synchronized (mLock) { SharedPreferences widgetSp = mContext.getSharedPreferences(String.valueOf(widgetId), Context.MODE_PRIVATE); - packageName = widgetSp.getString(PACKAGE_NAME, null); - shortcutId = widgetSp.getString(SHORTCUT_ID, null); - userId = widgetSp.getInt(USER_ID, INVALID_USER_ID); - key = PeopleSpaceUtils.getKey(shortcutId, packageName, userId); - if (key == null) { - if (DEBUG) Log.e(TAG, "Could not register " + widgetId); + key = new PeopleTileKey( + widgetSp.getString(SHORTCUT_ID, EMPTY_STRING), + widgetSp.getInt(USER_ID, INVALID_USER_ID), + widgetSp.getString(PACKAGE_NAME, EMPTY_STRING)); + if (!key.isValid()) { + if (DEBUG) Log.w(TAG, "Could not register listener for widget: " + widgetId); return; } } @@ -359,9 +379,9 @@ public class PeopleSpaceWidgetManager { if (DEBUG) Log.d(TAG, "Register listener for " + widgetId + " with " + key); mListeners.put(key, newListener); } - mPeopleManager.registerConversationListener(packageName, - userId, - shortcutId, newListener, + mPeopleManager.registerConversationListener(key.getPackageName(), + key.getUserId(), + key.getShortcutId(), newListener, mContext.getMainExecutor()); } @@ -371,27 +391,24 @@ public class PeopleSpaceWidgetManager { if (DEBUG) Log.d(TAG, "Widget removed: " + widgetId); mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_DELETED); // Retrieve storage needed for widget deletion. - String packageName; - String shortcutId; - int userId; - String key; + PeopleTileKey key; Set<String> storedWidgetIdsForKey; synchronized (mLock) { SharedPreferences widgetSp = mContext.getSharedPreferences(String.valueOf(widgetId), Context.MODE_PRIVATE); - packageName = widgetSp.getString(PACKAGE_NAME, null); - shortcutId = widgetSp.getString(SHORTCUT_ID, null); - userId = widgetSp.getInt(USER_ID, INVALID_USER_ID); - key = PeopleSpaceUtils.getKey(shortcutId, packageName, userId); - if (key == null) { + key = new PeopleTileKey( + widgetSp.getString(SHORTCUT_ID, null), + widgetSp.getInt(USER_ID, INVALID_USER_ID), + widgetSp.getString(PACKAGE_NAME, null)); + if (!key.isValid()) { if (DEBUG) Log.e(TAG, "Could not delete " + widgetId); return; } storedWidgetIdsForKey = new HashSet<>( - mSharedPrefs.getStringSet(key, new HashSet<>())); + mSharedPrefs.getStringSet(key.toString(), new HashSet<>())); } synchronized (mLock) { - PeopleSpaceUtils.removeStorageForTile(mContext, key, widgetId); + PeopleSpaceUtils.removeSharedPreferencesStorageForTile(mContext, key, widgetId); } // If another tile with the conversation is still stored, we need to keep the listener. if (DEBUG) Log.d(TAG, "Stored widget IDs: " + storedWidgetIdsForKey.toString()); @@ -399,13 +416,13 @@ public class PeopleSpaceWidgetManager { && storedWidgetIdsForKey.size() == 1) { if (DEBUG) Log.d(TAG, "Remove caching and listener"); unregisterConversationListener(key, widgetId); - uncacheConversationShortcut(shortcutId, packageName, userId); + uncacheConversationShortcut(key); } } } /** Unregisters the conversation listener for {@code appWidgetId}. */ - private void unregisterConversationListener(String key, int appWidgetId) { + private void unregisterConversationListener(PeopleTileKey key, int appWidgetId) { PeopleSpaceWidgetProvider.TileConversationListener registeredListener; synchronized (mListeners) { registeredListener = mListeners.get(key); @@ -420,12 +437,12 @@ public class PeopleSpaceWidgetManager { } /** Uncaches the conversation shortcut. */ - private void uncacheConversationShortcut(String shortcutId, String packageName, int userId) { + private void uncacheConversationShortcut(PeopleTileKey key) { try { - if (DEBUG) Log.d(TAG, "Uncaching shortcut for PeopleTile: " + shortcutId); - mLauncherApps.uncacheShortcuts(packageName, - Collections.singletonList(shortcutId), - UserHandle.of(userId), + if (DEBUG) Log.d(TAG, "Uncaching shortcut for PeopleTile: " + key.getShortcutId()); + mLauncherApps.uncacheShortcuts(key.getPackageName(), + Collections.singletonList(key.getShortcutId()), + UserHandle.of(key.getUserId()), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS); } catch (Exception e) { Log.d(TAG, "Exception uncaching shortcut:" + e); diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java index cccf7aa13028..3bc5b29bd05d 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java @@ -22,6 +22,7 @@ import android.app.people.PeopleManager; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; +import android.os.Bundle; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -67,18 +68,21 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider { ensurePeopleSpaceWidgetManagerInitialized(context); peopleSpaceWidgetManager.updateWidgets(appWidgetIds); for (int appWidgetId : appWidgetIds) { + if (DEBUG) Log.d(TAG, "Ensure listener is registered for widget: " + appWidgetId); PeopleSpaceWidgetProvider.TileConversationListener newListener = new PeopleSpaceWidgetProvider.TileConversationListener(); peopleSpaceWidgetManager.registerConversationListenerIfNeeded(appWidgetId, newListener); } - return; } - private void ensurePeopleSpaceWidgetManagerInitialized(Context context) { - if (peopleSpaceWidgetManager == null) { - peopleSpaceWidgetManager = new PeopleSpaceWidgetManager(context); - } + /** Called when widget updates. */ + @Override + public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, + int appWidgetId, Bundle newOptions) { + super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); + ensurePeopleSpaceWidgetManagerInitialized(context); + peopleSpaceWidgetManager.onAppWidgetOptionsChanged(appWidgetId, newOptions); } @Override @@ -88,6 +92,12 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider { peopleSpaceWidgetManager.deleteWidgets(appWidgetIds); } + private void ensurePeopleSpaceWidgetManagerInitialized(Context context) { + if (peopleSpaceWidgetManager == null) { + peopleSpaceWidgetManager = new PeopleSpaceWidgetManager(context); + } + } + @VisibleForTesting public void setPeopleSpaceWidgetManager(PeopleSpaceWidgetManager manager) { peopleSpaceWidgetManager = manager; diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java index 050352292b38..87b2a15d1c55 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java @@ -106,7 +106,7 @@ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.R PeopleSpaceTile tile = mTiles.get(i); String status = PeopleSpaceUtils.getLastInteractionString(mContext, - tile.getLastInteractionTimestamp(), true); + tile.getLastInteractionTimestamp()); personView.setTextViewText(R.id.status, status); personView.setTextViewText(R.id.name, tile.getUserName().toString()); diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleTileKey.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleTileKey.java new file mode 100644 index 000000000000..ac42cb08090a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleTileKey.java @@ -0,0 +1,105 @@ +/* + * 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.people.widget; + +import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_STRING; +import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID; + +import android.text.TextUtils; + +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import java.util.Objects; + +/** Class that encapsulates fields identifying a Conversation. */ +public class PeopleTileKey { + private String mShortcutId; + private int mUserId; + private String mPackageName; + + public PeopleTileKey(String shortcutId, int userId, String packageName) { + mShortcutId = shortcutId; + mUserId = userId; + mPackageName = packageName; + } + + public PeopleTileKey(NotificationEntry entry) { + mShortcutId = entry.getRanking() != null + && entry.getRanking().getConversationShortcutInfo() != null + ? entry.getRanking().getConversationShortcutInfo().getId() + : EMPTY_STRING; + mUserId = entry.getSbn().getUser() != null + ? entry.getSbn().getUser().getIdentifier() : INVALID_USER_ID; + mPackageName = entry.getSbn().getPackageName(); + } + + public String getShortcutId() { + return mShortcutId; + } + + public int getUserId() { + return mUserId; + } + + public String getPackageName() { + return mPackageName; + } + + /** Returns whether PeopleTileKey is valid/well-formed. */ + public boolean isValid() { + return !TextUtils.isEmpty(mShortcutId) && !TextUtils.isEmpty(mPackageName) && mUserId >= 0; + } + + /** + * Returns the uniquely identifying key for the conversation. + * + * <p>{@code userId} will always be a number, so we put user ID as the + * delimiter between the app-provided strings of shortcut ID and package name. + * + * <p>There aren't restrictions on shortcut ID characters, but there are restrictions requiring + * a {@code packageName} to always start with a letter. This restriction means we are + * guaranteed to avoid cases like "a/b/0/0/package.name" having two potential keys, as the first + * case is impossible given the package name restrictions: + * <ul> + * <li>"a/b" + "/" + 0 + "/" + "0/packageName"</li> + * <li>"a/b/0" + "/" + 0 + "/" + "packageName"</li> + * </ul> + */ + @Override + public String toString() { + if (!isValid()) return null; + return mShortcutId + "/" + mUserId + "/" + mPackageName; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof PeopleTileKey)) { + return false; + } + final PeopleTileKey o = (PeopleTileKey) other; + return Objects.equals(o.toString(), this.toString()); + } + + @Override + public int hashCode() { + return mPackageName.hashCode() + Integer.valueOf(mUserId).hashCode() + + mShortcutId.hashCode(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java index 7e20be6826dc..3d8784b29e4c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java @@ -94,7 +94,7 @@ public class QSFooterView extends FrameLayout { @Override protected void onFinishInflate() { super.onFinishInflate(); - mEdit = findViewById(android.R.id.edit); + mEdit = requireViewById(android.R.id.edit); mPageIndicator = findViewById(R.id.footer_page_indicator); @@ -104,14 +104,15 @@ public class QSFooterView extends FrameLayout { mMultiUserSwitch = findViewById(R.id.multi_user_switch); mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar); - mActionsContainer = findViewById(R.id.qs_footer_actions_container); + mActionsContainer = requireViewById(R.id.qs_footer_actions_container); mEditContainer = findViewById(R.id.qs_footer_actions_edit_container); mBuildText = findViewById(R.id.build); // RenderThread is doing more harm than good when touching the header (to expand quick // settings), so disable it for this view - ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true); - + if (mSettingsButton.getBackground() instanceof RippleDrawable) { + ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true); + } updateResources(); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); @@ -143,7 +144,7 @@ public class QSFooterView extends FrameLayout { int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space); mSettingsCogAnimator = new Builder() - .addFloat(mSettingsContainer, "translationX", + .addFloat(mSettingsButton, "translationX", isLayoutRtl() ? (remaining - defSpace) : -(remaining - defSpace), 0) .addFloat(mSettingsButton, "rotation", -120, 0) .build(); @@ -173,12 +174,15 @@ public class QSFooterView extends FrameLayout { @Nullable private TouchAnimator createFooterAnimator() { - return new TouchAnimator.Builder() + TouchAnimator.Builder builder = new TouchAnimator.Builder() .addFloat(mActionsContainer, "alpha", 0, 1) - .addFloat(mEditContainer, "alpha", 0, 1) .addFloat(mPageIndicator, "alpha", 0, 1) - .setStartDelay(0.9f) - .build(); + .addFloat(mBuildText, "alpha", 0, 1) + .setStartDelay(0.9f); + if (mEditContainer != null) { + builder.addFloat(mEditContainer, "alpha", 0, 1); + } + return builder.build(); } /** */ @@ -273,8 +277,10 @@ public class QSFooterView extends FrameLayout { mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility( isTunerEnabled ? View.VISIBLE : View.INVISIBLE); final boolean isDemo = UserManager.isDeviceInDemoMode(mContext); - mMultiUserSwitch.setVisibility(showUserSwitcher() ? View.VISIBLE : View.INVISIBLE); - mEditContainer.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE); + mMultiUserSwitch.setVisibility(showUserSwitcher() ? View.VISIBLE : View.GONE); + if (mEditContainer != null) { + mEditContainer.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE); + } mSettingsButton.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE); mBuildText.setVisibility(mExpanded && mShouldShowBuildText ? View.VISIBLE : View.GONE); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java index 2bea72cc0c7e..f1f4e16206a1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java @@ -153,8 +153,8 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme @Override protected void onViewAttached() { - if (mShowPMLiteButton) { - mPowerMenuLite.setVisibility(View.VISIBLE); + if (!mShowPMLiteButton) { + mPowerMenuLite.setVisibility(View.GONE); } mView.addOnLayoutChangeListener( (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 7657dcead583..ff9b9120c6e1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -32,6 +32,7 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewStub; import android.widget.LinearLayout; import com.android.internal.logging.UiEventLogger; @@ -127,8 +128,21 @@ public class QSPanel extends LinearLayout implements Tunable { } + protected void inflateQSFooter(boolean newFooter) { + ViewStub stub = findViewById(R.id.qs_footer_stub); + if (stub != null) { + stub.setLayoutResource( + newFooter ? R.layout.qs_footer_impl_two_lines : R.layout.qs_footer_impl); + stub.inflate(); + mFooter = findViewById(R.id.qs_footer); + } + } + void initialize(boolean sideLabels) { mSideLabels = sideLabels; + + inflateQSFooter(sideLabels); + mRegularTileLayout = createRegularTileLayout(); mTileLayout = mRegularTileLayout; @@ -344,7 +358,6 @@ public class QSPanel extends LinearLayout implements Tunable { @Override protected void onFinishInflate() { super.onFinishInflate(); - mFooter = findViewById(R.id.qs_footer); mDivider = findViewById(R.id.divider); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 9b66b59c06df..f51d7ef381ee 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -55,6 +55,11 @@ public class QuickQSPanel extends QSPanel { applyBottomMargin((View) mRegularTileLayout); } + @Override + protected void inflateQSFooter(boolean newFooter) { + // No footer + } + private void applyBottomMargin(View view) { int margin = getResources().getDimensionPixelSize(R.dimen.qs_header_tile_margin_bottom); MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index 56d06eb1b474..1699a34e6c08 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -51,6 +51,7 @@ import com.android.systemui.Dependency; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.State; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -95,6 +96,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener QSHost host, Looper backgroundLooper, Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -102,8 +104,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener String action, Context userContext ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mWindowManager = WindowManagerGlobal.getWindowManagerService(); mComponent = ComponentName.unflattenFromString(action); mTile = new Tile(); @@ -450,6 +452,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener final Lazy<QSHost> mQSHostLazy; final Looper mBackgroundLooper; final Handler mMainHandler; + private final FalsingManager mFalsingManager; final MetricsLogger mMetricsLogger; final StatusBarStateController mStatusBarStateController; final ActivityStarter mActivityStarter; @@ -463,6 +466,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener Lazy<QSHost> hostLazy, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -471,6 +475,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener mQSHostLazy = hostLazy; mBackgroundLooper = backgroundLooper; mMainHandler = mainHandler; + mFalsingManager = falsingManager; mMetricsLogger = metricsLogger; mStatusBarStateController = statusBarStateController; mActivityStarter = activityStarter; @@ -496,6 +501,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener mQSHostLazy.get(), mBackgroundLooper, mMainHandler, + mFalsingManager, mMetricsLogger, mStatusBarStateController, mActivityStarter, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index 6983b38489f6..9e5fe732cd0c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -30,6 +30,7 @@ import com.android.systemui.plugins.qs.QSTileView; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.tiles.AirplaneModeTile; +import com.android.systemui.qs.tiles.AlarmTile; import com.android.systemui.qs.tiles.BatterySaverTile; import com.android.systemui.qs.tiles.BluetoothTile; import com.android.systemui.qs.tiles.CameraToggleTile; @@ -91,6 +92,7 @@ public class QSFactoryImpl implements QSFactory { private final Provider<CameraToggleTile> mCameraToggleTileProvider; private final Provider<MicrophoneToggleTile> mMicrophoneToggleTileProvider; private final Provider<DeviceControlsTile> mDeviceControlsTileProvider; + private final Provider<AlarmTile> mAlarmTileProvider; private final Lazy<QSHost> mQsHostLazy; private final Provider<CustomTile.Builder> mCustomTileBuilderProvider; @@ -126,7 +128,8 @@ public class QSFactoryImpl implements QSFactory { Provider<ReduceBrightColorsTile> reduceBrightColorsTileProvider, Provider<CameraToggleTile> cameraToggleTileProvider, Provider<MicrophoneToggleTile> microphoneToggleTileProvider, - Provider<DeviceControlsTile> deviceControlsTileProvider) { + Provider<DeviceControlsTile> deviceControlsTileProvider, + Provider<AlarmTile> alarmTileProvider) { mQsHostLazy = qsHostLazy; mCustomTileBuilderProvider = customTileBuilderProvider; @@ -157,6 +160,7 @@ public class QSFactoryImpl implements QSFactory { mCameraToggleTileProvider = cameraToggleTileProvider; mMicrophoneToggleTileProvider = microphoneToggleTileProvider; mDeviceControlsTileProvider = deviceControlsTileProvider; + mAlarmTileProvider = alarmTileProvider; } public QSTile createTile(String tileSpec) { @@ -218,6 +222,8 @@ public class QSFactoryImpl implements QSFactory { return mMicrophoneToggleTileProvider.get(); case "controls": return mDeviceControlsTileProvider.get(); + case "alarm": + return mAlarmTileProvider.get(); } // Custom tiles diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java index 5a81676567a7..f9d1def3b716 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java @@ -58,6 +58,7 @@ import com.android.settingslib.Utils; import com.android.systemui.Dumpable; import com.android.systemui.Prefs; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; @@ -103,6 +104,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy private final StatusBarStateController mStatusBarStateController; protected final ActivityStarter mActivityStarter; private final UiEventLogger mUiEventLogger; + private final FalsingManager mFalsingManager; private final QSLogger mQSLogger; private volatile int mReadyState; @@ -159,6 +161,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy QSHost host, Looper backgroundLooper, Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -171,6 +174,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy mUiHandler = mainHandler; mHandler = new H(backgroundLooper); + mFalsingManager = falsingManager; mQSLogger = qsLogger; mMetricsLogger = metricsLogger; mStatusBarStateController = statusBarStateController; @@ -608,7 +612,9 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy mContext, mEnforcedAdmin); mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); } else { - handleClick(); + if (!mFalsingManager.isFalseTap(true, 0.1)) { + handleClick(); + } } } else if (msg.what == SECONDARY_CLICK) { name = "handleSecondaryClick"; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java index b8485907c519..07abb90f631c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java @@ -38,6 +38,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.GlobalSetting; @@ -63,6 +64,7 @@ public class AirplaneModeTile extends QSTileImpl<BooleanState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -70,8 +72,8 @@ public class AirplaneModeTile extends QSTileImpl<BooleanState> { BroadcastDispatcher broadcastDispatcher, Lazy<ConnectivityManager> lazyConnectivityManager ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mBroadcastDispatcher = broadcastDispatcher; mLazyConnectivityManager = lazyConnectivityManager; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt new file mode 100644 index 000000000000..2945c6b4e22a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt @@ -0,0 +1,120 @@ +package com.android.systemui.qs.tiles + +import android.app.AlarmManager +import android.app.AlarmManager.AlarmClockInfo +import android.content.Intent +import android.os.Handler +import android.os.Looper +import android.provider.AlarmClock +import android.service.quicksettings.Tile +import android.text.TextUtils +import android.text.format.DateFormat +import androidx.annotation.VisibleForTesting +import com.android.internal.logging.MetricsLogger +import com.android.systemui.R +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.plugins.qs.QSTile +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.settings.UserTracker +import com.android.systemui.statusbar.FeatureFlags +import com.android.systemui.statusbar.policy.NextAlarmController +import java.util.Locale +import javax.inject.Inject + +class AlarmTile @Inject constructor( + host: QSHost, + @Background backgroundLooper: Looper, + @Main mainHandler: Handler, + falsingManager: FalsingManager, + metricsLogger: MetricsLogger, + statusBarStateController: StatusBarStateController, + activityStarter: ActivityStarter, + qsLogger: QSLogger, + private val featureFlags: FeatureFlags, + private val userTracker: UserTracker, + nextAlarmController: NextAlarmController +) : QSTileImpl<QSTile.State>( + host, + backgroundLooper, + mainHandler, + falsingManager, + metricsLogger, + statusBarStateController, + activityStarter, + qsLogger +) { + + private var lastAlarmInfo: AlarmManager.AlarmClockInfo? = null + private val icon = ResourceIcon.get(R.drawable.ic_alarm) + @VisibleForTesting + internal val defaultIntent = Intent(AlarmClock.ACTION_SET_ALARM) + private val callback = NextAlarmController.NextAlarmChangeCallback { nextAlarm -> + lastAlarmInfo = nextAlarm + refreshState() + } + + init { + nextAlarmController.observe(this, callback) + } + + override fun isAvailable(): Boolean { + return featureFlags.isAlarmTileAvailable + } + + override fun newTileState(): QSTile.State { + return QSTile.State().apply { + handlesLongClick = false + } + } + + private fun startDefaultSetAlarm() { + mActivityStarter.postStartActivityDismissingKeyguard(defaultIntent, 0) + } + + override fun handleClick() { + lastAlarmInfo?.showIntent?.let { + mActivityStarter.postStartActivityDismissingKeyguard(it) + } ?: startDefaultSetAlarm() + } + + override fun handleUpdateState(state: QSTile.State, arg: Any?) { + state.icon = icon + state.label = tileLabel + lastAlarmInfo?.let { + state.secondaryLabel = formatNextAlarm(it) + state.state = Tile.STATE_ACTIVE + } ?: run { + state.secondaryLabel = mContext.getString(R.string.qs_alarm_tile_no_alarm) + state.state = Tile.STATE_INACTIVE + } + state.contentDescription = TextUtils.concat(state.label, ", ", state.secondaryLabel) + } + + override fun getTileLabel(): CharSequence { + return mContext.getString(R.string.status_bar_alarm) + } + + private fun formatNextAlarm(info: AlarmClockInfo): String { + val skeleton = if (use24HourFormat()) "EHm" else "Ehma" + val pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton) + return DateFormat.format(pattern, info.triggerTime).toString() + } + + private fun use24HourFormat(): Boolean { + return DateFormat.is24HourFormat(mContext, userTracker.userId) + } + + override fun getMetricsCategory(): Int { + return 0 + } + + override fun getLongClickIntent(): Intent? { + return null + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java index bf3e4be9b9db..49d3ff9439d6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java @@ -29,6 +29,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -59,6 +60,7 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -66,8 +68,8 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements BatteryController batteryController, SecureSettings secureSettings ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mBatteryController = batteryController; mBatteryController.observe(getLifecycle(), this); int currentUser = host.getUserContext().getUserId(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 1424244b6729..56df4d8de6c6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -42,6 +42,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -70,14 +71,15 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, BluetoothController bluetoothController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mController = bluetoothController; mDetailAdapter = (BluetoothDetailAdapter) createDetailAdapter(); mController.observe(getLifecycle(), mCallback); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java index 70287cd37d01..0d73a5a97706 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java @@ -21,7 +21,6 @@ import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import static com.android.systemui.DejankUtils.whitelistIpcs; -import android.hardware.SensorPrivacyManager; import android.hardware.SensorPrivacyManager.Sensors.Sensor; import android.os.Handler; import android.os.Looper; @@ -35,6 +34,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.logging.QSLogger; @@ -50,13 +50,15 @@ public class CameraToggleTile extends SensorPrivacyToggleTile { @Background Looper backgroundLooper, @Main Handler mainHandler, MetricsLogger metricsLogger, + FalsingManager falsingManager, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, IndividualSensorPrivacyController sensorPrivacyController, KeyguardStateController keyguardStateController) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger, sensorPrivacyController, keyguardStateController); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger, sensorPrivacyController, + keyguardStateController); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index f03ce2c0b267..fa99eed150e3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -40,6 +40,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -81,6 +82,7 @@ public class CastTile extends QSTileImpl<BooleanState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -90,8 +92,8 @@ public class CastTile extends QSTileImpl<BooleanState> { NetworkController networkController, HotspotController hotspotController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mController = castController; mDetailAdapter = new CastDetailAdapter(); mKeyguard = keyguardStateController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 6a574d1d314b..8cc6ff254083 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -45,6 +45,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile.SignalState; @@ -76,14 +77,15 @@ public class CellularTile extends QSTileImpl<SignalState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, NetworkController networkController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mController = networkController; mDataController = mController.getMobileDataController(); mDetailAdapter = new CellularDetailAdapter(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java index a6d96042d5af..ca7cf8319d32 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -32,6 +32,7 @@ import com.android.systemui.R.drawable; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -60,6 +61,7 @@ public class ColorInversionTile extends QSTileImpl<BooleanState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -67,8 +69,8 @@ public class ColorInversionTile extends QSTileImpl<BooleanState> { UserTracker userTracker, SecureSettings secureSettings ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mSetting = new SecureSetting(secureSettings, mHandler, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, userTracker.getUserId()) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java index 85f12458c33a..61376f0610a4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java @@ -29,6 +29,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -49,14 +50,15 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, DataSaverController dataSaverController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mDataSaverController = dataSaverController; mDataSaverController.observe(getLifecycle(), this); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt index 3b9f5dc8ea03..a74a50e7d6c2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt @@ -16,6 +16,7 @@ package com.android.systemui.qs.tiles +import android.content.ComponentName import android.content.Intent import android.os.Handler import android.os.Looper @@ -27,10 +28,12 @@ import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.dagger.ControlsComponent import com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE import com.android.systemui.controls.management.ControlsListingController -import com.android.systemui.controls.ui.ControlsDialog +import com.android.systemui.controls.ui.ControlsActivity +import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost @@ -40,24 +43,24 @@ import com.android.systemui.statusbar.FeatureFlags import com.android.systemui.util.settings.GlobalSettings import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject -import javax.inject.Provider class DeviceControlsTile @Inject constructor( host: QSHost, @Background backgroundLooper: Looper, @Main mainHandler: Handler, + falsingManager: FalsingManager, metricsLogger: MetricsLogger, statusBarStateController: StatusBarStateController, activityStarter: ActivityStarter, qsLogger: QSLogger, private val controlsComponent: ControlsComponent, private val featureFlags: FeatureFlags, - private val dialogProvider: Provider<ControlsDialog>, globalSettings: GlobalSettings ) : QSTileImpl<QSTile.State>( host, backgroundLooper, mainHandler, + falsingManager, metricsLogger, statusBarStateController, activityStarter, @@ -72,7 +75,6 @@ class DeviceControlsTile @Inject constructor( private var hasControlsApps = AtomicBoolean(false) private val intent = Intent(Settings.ACTION_DEVICE_CONTROLS_SETTINGS) - private var controlsDialog: ControlsDialog? = null private val icon = ResourceIcon.get(R.drawable.ic_device_light) private val listingCallback = object : ControlsListingController.ControlsListingCallback { @@ -102,27 +104,19 @@ class DeviceControlsTile @Inject constructor( } override fun handleDestroy() { - dismissDialog() super.handleDestroy() } - private fun createDialog() { - if (controlsDialog?.isShowing != true) { - controlsDialog = dialogProvider.get() - } - } - - private fun dismissDialog() { - controlsDialog?.dismiss()?.also { - controlsDialog = null - } - } - override fun handleClick() { if (state.state == Tile.STATE_ACTIVE) { mUiHandler.post { - createDialog() - controlsDialog?.show(controlsComponent.getControlsUiController().get()) + mHost.collapsePanels() + val i = Intent().apply { + component = ComponentName(mContext, ControlsActivity::class.java) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + putExtra(ControlsUiController.BACK_TO_GLOBAL_ACTIONS, false) + } + mContext.startActivity(i) } } } @@ -133,9 +127,6 @@ class DeviceControlsTile @Inject constructor( state.contentDescription = state.label state.icon = icon if (controlsComponent.isEnabled() && hasControlsApps.get()) { - if (controlsDialog == null) { - mUiHandler.post(this::createDialog) - } if (controlsComponent.getVisibility() == AVAILABLE) { state.state = Tile.STATE_ACTIVE state.secondaryLabel = "" @@ -146,7 +137,6 @@ class DeviceControlsTile @Inject constructor( state.stateDescription = state.secondaryLabel } else { state.state = Tile.STATE_UNAVAILABLE - dismissDialog() } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index 7ec2691f3a04..4b96cf3dbf16 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -54,6 +54,7 @@ import com.android.systemui.SysUIToast; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -87,6 +88,7 @@ public class DndTile extends QSTileImpl<BooleanState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -94,8 +96,8 @@ public class DndTile extends QSTileImpl<BooleanState> { ZenModeController zenModeController, @Main SharedPreferences sharedPreferences ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mController = zenModeController; mSharedPreferences = sharedPreferences; mDetailAdapter = new DndDetailAdapter(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index cd45082458f2..31a98db033f9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -30,6 +30,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -51,14 +52,15 @@ public class FlashlightTile extends QSTileImpl<BooleanState> implements QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, FlashlightController flashlightController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mFlashlightController = flashlightController; mFlashlightController.observe(getLifecycle(), this); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index a45d94ace425..4e0f634ce22c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -32,6 +32,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -57,6 +58,7 @@ public class HotspotTile extends QSTileImpl<BooleanState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -64,8 +66,8 @@ public class HotspotTile extends QSTileImpl<BooleanState> { HotspotController hotspotController, DataSaverController dataSaverController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mHotspotController = hotspotController; mDataSaverController = dataSaverController; mHotspotController.observe(this, mCallbacks); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java index e1a1fd2679c5..14a3fc0bcd73 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java @@ -40,9 +40,9 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; -import com.android.systemui.plugins.qs.QSTile.Icon; import com.android.systemui.plugins.qs.QSTile.SignalState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.AlphaControlledSignalTileView; @@ -80,14 +80,15 @@ public class InternetTile extends QSTileImpl<SignalState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, NetworkController networkController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mController = networkController; mDataController = mController.getMobileDataController(); mController.observe(getLifecycle(), mSignalCallback); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java index d502d06efceb..830a1fd57d7f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java @@ -30,6 +30,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -55,6 +56,7 @@ public class LocationTile extends QSTileImpl<BooleanState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -62,8 +64,8 @@ public class LocationTile extends QSTileImpl<BooleanState> { LocationController locationController, KeyguardStateController keyguardStateController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mController = locationController; mKeyguard = keyguardStateController; mController.observe(this, mCallback); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java index e9b712df2154..b8d879226f55 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java @@ -21,7 +21,6 @@ import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE; import static com.android.systemui.DejankUtils.whitelistIpcs; -import android.hardware.SensorPrivacyManager; import android.hardware.SensorPrivacyManager.Sensors.Sensor; import android.os.Handler; import android.os.Looper; @@ -35,6 +34,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.logging.QSLogger; @@ -50,13 +50,15 @@ public class MicrophoneToggleTile extends SensorPrivacyToggleTile { @Background Looper backgroundLooper, @Main Handler mainHandler, MetricsLogger metricsLogger, + FalsingManager falsingManager, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, IndividualSensorPrivacyController sensorPrivacyController, KeyguardStateController keyguardStateController) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger, sensorPrivacyController, keyguardStateController); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger, sensorPrivacyController, + keyguardStateController); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java index 63e27796f441..6ac2f9ae202a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java @@ -36,6 +36,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -60,14 +61,15 @@ public class NfcTile extends QSTileImpl<BooleanState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, BroadcastDispatcher broadcastDispatcher ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mBroadcastDispatcher = broadcastDispatcher; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java index d8548decc5f4..536908639def 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java @@ -40,6 +40,7 @@ import com.android.systemui.dagger.NightDisplayListenerModule; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -78,6 +79,7 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -86,8 +88,8 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements ColorDisplayManager colorDisplayManager, NightDisplayListenerModule.Builder nightDisplayListenerBuilder ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mLocationController = locationController; mManager = colorDisplayManager; mNightDisplayListenerBuilder = nightDisplayListenerBuilder; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java index aec7b9a4b6b1..479be659ba10 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java @@ -30,6 +30,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -57,13 +58,14 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mReduceBrightColorsController = reduceBrightColorsController; mReduceBrightColorsController.observe(getLifecycle(), this); mIsAvailable = isAvailable; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java index c46cc4f9aa0a..173cc0597b0b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java @@ -31,6 +31,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -52,14 +53,15 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, RotationLockController rotationLockController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mController = rotationLockController; mController.observe(this, mCallback); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java index 0f0a9a2766f1..6845dc593aa3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java @@ -29,6 +29,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -55,6 +56,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -62,8 +64,8 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> RecordingController controller, KeyguardDismissUtil keyguardDismissUtil ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mController = controller; mController.observe(this, mCallback); mKeyguardDismissUtil = keyguardDismissUtil; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java index 0c582bdbe12f..a492330c1796 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java @@ -29,6 +29,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -59,14 +60,15 @@ public abstract class SensorPrivacyToggleTile extends QSTileImpl<QSTile.BooleanS protected SensorPrivacyToggleTile(QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, IndividualSensorPrivacyController sensorPrivacyController, KeyguardStateController keyguardStateController) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mSensorPrivacyController = sensorPrivacyController; mKeyguard = keyguardStateController; mSensorPrivacyController.observe(getLifecycle(), this); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java index 78975a4798ce..0ef5bc8f926b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java @@ -32,6 +32,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -66,6 +67,7 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -74,8 +76,8 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements BatteryController batteryController, LocationController locationController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mBatteryController = batteryController; mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class); mLocationController = locationController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java index a6cddd3367d3..2590f374a662 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java @@ -28,6 +28,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.State; @@ -51,6 +52,7 @@ public class UserTile extends QSTileImpl<State> implements UserInfoController.On QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -58,8 +60,8 @@ public class UserTile extends QSTileImpl<State> implements UserInfoController.On UserSwitcherController userSwitcherController, UserInfoController userInfoController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mUserSwitcherController = userSwitcherController; mUserInfoController = userInfoController; mUserInfoController.observe(getLifecycle(), this); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 341e67c9393f..dab68ed30c2b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -37,6 +37,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; @@ -77,6 +78,7 @@ public class WifiTile extends QSTileImpl<SignalState> { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, @@ -84,8 +86,8 @@ public class WifiTile extends QSTileImpl<SignalState> { NetworkController networkController, AccessPointController accessPointController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mController = networkController; mWifiController = accessPointController; mDetailAdapter = (WifiDetailAdapter) createDetailAdapter(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java index 5235b6d5a0bb..c88a002ddf92 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java @@ -29,6 +29,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -50,14 +51,15 @@ public class WorkModeTile extends QSTileImpl<BooleanState> implements QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, ManagedProfileController managedProfileController ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); mProfileController = managedProfileController; mProfileController.observe(getLifecycle(), this); } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java index c066619d049a..bb8c36776d57 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java @@ -136,7 +136,7 @@ public class CropView extends View { case MotionEvent.ACTION_UP: if (mCurrentDraggingBoundary != CropBoundary.NONE) { // Commit the delta to the stored crop values. - commitDeltas(); + commitDeltas(mCurrentDraggingBoundary); updateListener(event); } } @@ -184,12 +184,12 @@ public class CropView extends View { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - commitDeltas(); + commitDeltas(boundary); } @Override public void onAnimationCancel(Animator animation) { - commitDeltas(); + commitDeltas(boundary); } }); animator.setFloatValues(0f, 1f); @@ -228,11 +228,14 @@ public class CropView extends View { mCropInteractionListener = listener; } - private void commitDeltas() { - mTopCrop += mTopDelta; - mBottomCrop += mBottomDelta; - mTopDelta = 0; - mBottomDelta = 0; + private void commitDeltas(CropBoundary boundary) { + if (boundary == CropBoundary.TOP) { + mTopCrop += mTopDelta; + mTopDelta = 0; + } else if (boundary == CropBoundary.BOTTOM) { + mBottomCrop += mBottomDelta; + mBottomDelta = 0; + } } private void updateListener(MotionEvent event) { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java index 4dc846e0e95d..db997053af23 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java @@ -339,14 +339,22 @@ public class LongScreenshotActivity extends Activity { } @Override - public void onComplete(ImageTileSet imageTileSet) { + public void onComplete(ImageTileSet imageTileSet, int pageSize) { Log.i(TAG, "Got tiles " + imageTileSet.getWidth() + " x " + imageTileSet.getHeight()); mPreview.setImageDrawable(imageTileSet.getDrawable()); updateCropLocation(); mMagnifierView.setDrawable(imageTileSet.getDrawable(), imageTileSet.getWidth(), imageTileSet.getHeight()); - mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f); + // Original boundaries go from the image tile set's y=0 to y=pageSize, so + // we animate to that as a starting crop position. + float topFraction = Math.max(0, + -imageTileSet.getTop() / (float) imageTileSet.getHeight()); + float bottomFraction = Math.min(1f, + 1 - (imageTileSet.getBottom() - pageSize) + / (float) imageTileSet.getHeight()); + mCropView.animateBoundaryTo(CropView.CropBoundary.TOP, topFraction); + mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, bottomFraction); mBackgroundExecutor.execute(() -> saveCacheBitmap(imageTileSet)); } }); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS b/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS new file mode 100644 index 000000000000..9b3e386bc0d8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS @@ -0,0 +1,12 @@ +# Scroll Capture (Long Screenshots) +# Bug component: 801322 +# +# Referenced by: +# +# core/java/src/android/view/OWNERS +# core/java/src/com/android/internal/view/OWNERS +# core/tests/coretests/src/android/view/OWNERS +# core/tests/coretests/src/com/android/internal/view/OWNERS + +mrcasey@google.com +mrenouf@google.com diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java index b62e2c34ed6e..34094cd81120 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java @@ -171,7 +171,7 @@ public class ScrollCaptureController { if (mImageTileSet.isEmpty()) { mCaptureCallback.onError(); } else { - mCaptureCallback.onComplete(mImageTileSet); + mCaptureCallback.onComplete(mImageTileSet, session.getPageHeight()); } } @@ -179,7 +179,7 @@ public class ScrollCaptureController { * Callback for image capture completion or error. */ public interface ScrollCaptureCallback { - void onComplete(ImageTileSet imageTileSet); + void onComplete(ImageTileSet imageTileSet, int pageHeight); void onError(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index c4fa6df56775..059903961eae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -141,6 +141,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< private static final int MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND = 57 << MSG_SHIFT; //TODO(b/169175022) Update name and when feature name is locked. private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE = 58 << MSG_SHIFT; + private static final int MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED = 59 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -369,6 +370,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< * Handles a window manager shell logging command. */ default void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {} + + /** + * @see IStatusBar#setNavigationBarLumaSamplingEnabled(int, boolean) + */ + default void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {} } public CommandQueue(Context context) { @@ -1019,6 +1025,14 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } @Override + public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) { + synchronized (mLock) { + mHandler.obtainMessage(MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED, displayId, + enable ? 1 : 0).sendToTarget(); + } + } + + @Override public void passThroughShellCommand(String[] args, ParcelFileDescriptor pfd) { final FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor()); final PrintWriter pw = new PrintWriter(fos); @@ -1400,6 +1414,12 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } args.recycle(); break; + case MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED: + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).setNavigationBarLumaSamplingEnabled(msg.arg1, + msg.arg2 != 0); + } + break; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java index 1d59257c9c4f..c8e0d60ce304 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java @@ -90,4 +90,8 @@ public class FeatureFlags { public boolean isPMLiteEnabled() { return mFlagReader.isEnabled(R.bool.flag_pm_lite); } + + public boolean isAlarmTileAvailable() { + return mFlagReader.isEnabled(R.bool.flag_alarm_tile); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java index 992015320fa0..e090d0b13205 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java @@ -31,6 +31,7 @@ import android.widget.TextView; import com.android.internal.R; import com.android.internal.widget.CachingIconView; import com.android.internal.widget.ConversationLayout; +import com.android.internal.widget.ImageFloatingTextView; import com.android.internal.widget.NotificationExpandButton; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationContentView; @@ -430,6 +431,8 @@ public class NotificationGroupingUtil { public static final int[] MARGIN_ADJUSTED_VIEWS = { R.id.notification_headerless_view_column, + R.id.text, + R.id.big_text, R.id.title, R.id.notification_main_column, R.id.notification_header}; @@ -458,6 +461,10 @@ public class NotificationGroupingUtil { if (target == null) { return; } + if (target instanceof ImageFloatingTextView) { + ((ImageFloatingTextView) target).setHasImage(iconVisible); + return; + } final Integer data = (Integer) target.getTag(iconVisible ? com.android.internal.R.id.tag_margin_end_when_icon_visible : com.android.internal.R.id.tag_margin_end_when_icon_gone); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 3496581b1b8a..e1199077efb9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -16,9 +16,6 @@ package com.android.systemui.statusbar; -import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN_REVERSE; -import static com.android.systemui.statusbar.phone.NotificationIconContainer.IconState.NO_VALUE; - import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -34,7 +31,6 @@ import android.view.WindowInsets; import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationUtils; @@ -55,8 +51,6 @@ import com.android.systemui.statusbar.phone.NotificationIconContainer; public class NotificationShelf extends ActivatableNotificationView implements View.OnLayoutChangeListener, StateListener { - private static final boolean USE_ANIMATIONS_WHEN_OPENING = - SystemProperties.getBoolean("debug.icon_opening_animations", true); private static final boolean ICON_ANMATIONS_WHILE_SCROLLING = SystemProperties.getBoolean("debug.icon_scroll_animations", true); private static final int TAG_CONTINUOUS_CLIPPING = R.id.continuous_clipping_tag; @@ -174,18 +168,9 @@ public class NotificationShelf extends ActivatableNotificationView implements float viewEnd = lastViewState.yTranslation + lastViewState.height; viewState.copyFrom(lastViewState); viewState.height = getIntrinsicHeight(); - viewState.yTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - viewState.height, getFullyClosedTranslation()); viewState.zTranslation = ambientState.getBaseZHeight(); - // For the small display size, it's not enough to make the icon not covered by - // the top cutout so the denominator add the height of cutout. - // Totally, (getIntrinsicHeight() * 2 + mCutoutHeight) should be smaller then - // mAmbientState.getTopPadding(). - float openedAmount = (viewState.yTranslation - getFullyClosedTranslation()) - / (getIntrinsicHeight() * 2 + mCutoutHeight); - openedAmount = Math.min(1.0f, openedAmount); - viewState.openedAmount = openedAmount; viewState.clipTopAmount = 0; viewState.alpha = 1; viewState.belowSpeedBump = mHostLayoutController.getSpeedBumpIndex() == 0; @@ -220,11 +205,6 @@ public class NotificationShelf extends ActivatableNotificationView implements View lastChild = mAmbientState.getLastVisibleBackgroundChild(); mNotGoneIndex = -1; float interpolationStart = mMaxLayoutHeight - getIntrinsicHeight() * 2; - float expandAmount = 0.0f; - if (shelfStart >= interpolationStart) { - expandAmount = (shelfStart - interpolationStart) / getIntrinsicHeight(); - expandAmount = Math.min(1.0f, expandAmount); - } // find the first view that doesn't overlap with the shelf int notGoneIndex = 0; int colorOfViewBeforeLast = NO_COLOR; @@ -239,7 +219,6 @@ public class NotificationShelf extends ActivatableNotificationView implements boolean scrollingFast = currentScrollVelocity > mScrollFastThreshold || (mAmbientState.isExpansionChanging() && Math.abs(mAmbientState.getExpandingVelocity()) > mScrollFastThreshold); - boolean scrolling = currentScrollVelocity > 0; boolean expandingAnimated = mAmbientState.isExpansionChanging() && !mAmbientState.isPanelTracking(); int baseZHeight = mAmbientState.getBaseZHeight(); @@ -249,8 +228,7 @@ public class NotificationShelf extends ActivatableNotificationView implements ActivatableNotificationView previousAnv = null; for (int i = 0; i < mHostLayoutController.getChildCount(); i++) { - ExpandableView child = (ExpandableView) mHostLayoutController.getChildAt(i); - + ExpandableView child = mHostLayoutController.getChildAt(i); if (!child.needsClippingToShelf() || child.getVisibility() == GONE) { continue; } @@ -268,9 +246,8 @@ public class NotificationShelf extends ActivatableNotificationView implements int clipTop = updateNotificationClipHeight(child, notificationClipEnd, notGoneIndex); clipTopAmount = Math.max(clipTop, clipTopAmount); - - float inShelfAmount = updateShelfTransformation(child, expandAmount, scrolling, - scrollingFast, expandingAnimated, isLastChild); + final float inShelfAmount = updateShelfTransformation(child, scrollingFast, + expandingAnimated, isLastChild); // If the current row is an ExpandableNotificationRow, update its color, roundedness, // and icon state. if (child instanceof ExpandableNotificationRow) { @@ -498,56 +475,40 @@ public class NotificationShelf extends ActivatableNotificationView implements /** * @return the amount how much this notification is in the shelf */ - private float updateShelfTransformation(ExpandableView view, float expandAmount, - boolean scrolling, boolean scrollingFast, boolean expandingAnimated, - boolean isLastChild) { - StatusBarIconView icon = view.getShelfIcon(); - NotificationIconContainer.IconState iconState = getIconState(icon); + private float updateShelfTransformation(ExpandableView view, boolean scrollingFast, + boolean expandingAnimated, boolean isLastChild) { // Let calculate how much the view is in the shelf float viewStart = view.getTranslationY(); int fullHeight = view.getActualHeight() + mPaddingBetweenElements; float iconTransformStart = calculateIconTransformationStart(view); - float transformDistance = getIntrinsicHeight() * 1.5f; - transformDistance *= NotificationUtils.interpolate(1.f, 1.5f, expandAmount); - transformDistance = Math.min(transformDistance, fullHeight); - // Let's make sure the transform distance is // at most to the icon (relevant for conversations) - transformDistance = Math.min(viewStart + fullHeight - iconTransformStart, - transformDistance); + float transformDistance = Math.min( + viewStart + fullHeight - iconTransformStart, + getIntrinsicHeight()); if (isLastChild) { fullHeight = Math.min(fullHeight, view.getMinHeight() - getIntrinsicHeight()); - transformDistance = Math.min(transformDistance, view.getMinHeight() - - getIntrinsicHeight()); + transformDistance = Math.min( + transformDistance, + view.getMinHeight() - getIntrinsicHeight()); } float viewEnd = viewStart + fullHeight; - handleCustomTransformHeight(view, expandingAnimated, iconState); - - float fullTransitionAmount; - float iconTransitionAmount; - float contentTransformationAmount; + float fullTransitionAmount = 0.0f; + float iconTransitionAmount = 0.0f; float shelfStart = getTranslationY(); - boolean fullyInOrOut = true; - if (viewEnd >= shelfStart && (!mAmbientState.isUnlockHintRunning() || view.isInShelf()) + + if (viewEnd >= shelfStart + && (!mAmbientState.isUnlockHintRunning() || view.isInShelf()) && (mAmbientState.isShadeExpanded() || (!view.isPinned() && !view.isHeadsUpAnimatingAway()))) { - if (viewStart < shelfStart) { - if (iconState != null && iconState.hasCustomTransformHeight()) { - fullHeight = iconState.customTransformHeight; - transformDistance = iconState.customTransformHeight; - } + if (viewStart < shelfStart) { float fullAmount = (shelfStart - viewStart) / fullHeight; fullAmount = Math.min(1.0f, fullAmount); - float interpolatedAmount = Interpolators.ACCELERATE_DECELERATE.getInterpolation( - fullAmount); - interpolatedAmount = NotificationUtils.interpolate( - interpolatedAmount, fullAmount, expandAmount); - fullTransitionAmount = 1.0f - interpolatedAmount; - + fullTransitionAmount = 1.0f - fullAmount; if (isLastChild) { // Reduce icon transform distance to completely fade in shelf icon // by the time the notification icon fades out, and vice versa @@ -558,37 +519,14 @@ public class NotificationShelf extends ActivatableNotificationView implements } iconTransitionAmount = MathUtils.constrain(iconTransitionAmount, 0.0f, 1.0f); iconTransitionAmount = 1.0f - iconTransitionAmount; - fullyInOrOut = false; } else { + // Fully in shelf. fullTransitionAmount = 1.0f; iconTransitionAmount = 1.0f; } - - // Transforming the content - contentTransformationAmount = (shelfStart - viewStart) / transformDistance; - contentTransformationAmount = Math.min(1.0f, contentTransformationAmount); - contentTransformationAmount = 1.0f - contentTransformationAmount; - } else { - fullTransitionAmount = 0.0f; - iconTransitionAmount = 0.0f; - contentTransformationAmount = 0.0f; - } - if (iconState != null && fullyInOrOut && !expandingAnimated && iconState.isLastExpandIcon) { - iconState.isLastExpandIcon = false; - iconState.customTransformHeight = NO_VALUE; } - - // Update the content transformation amount - if (view.isAboveShelf() || view.showingPulsing() - || (!isLastChild && iconState != null && !iconState.translateContent)) { - contentTransformationAmount = 0.0f; - } - view.setContentTransformationAmount(contentTransformationAmount, isLastChild); - - // Update the positioning of the icon - updateIconPositioning(view, iconTransitionAmount, fullTransitionAmount, - transformDistance, scrolling, scrollingFast, expandingAnimated, isLastChild); - + updateIconPositioning(view, iconTransitionAmount, + scrollingFast, expandingAnimated, isLastChild); return fullTransitionAmount; } @@ -607,87 +545,31 @@ public class NotificationShelf extends ActivatableNotificationView implements return start; } - private void handleCustomTransformHeight(ExpandableView view, boolean expandingAnimated, - NotificationIconContainer.IconState iconState) { - if (iconState != null && expandingAnimated && mAmbientState.getScrollY() == 0 - && !mAmbientState.isOnKeyguard() && !iconState.isLastExpandIcon) { - // We are expanding animated. Because we switch to a linear interpolation in this case, - // the last icon may be stuck in between the shelf position and the notification - // position, which looks pretty bad. We therefore optimize this case by applying a - // shorter transition such that the icon is either fully in the notification or we clamp - // it into the shelf if it's close enough. - // We need to persist this, since after the expansion, the behavior should still be the - // same. - float position = mAmbientState.getIntrinsicPadding() - + mHostLayoutController.getPositionInLinearLayout(view); - int maxShelfStart = mMaxLayoutHeight - getIntrinsicHeight(); - if (position < maxShelfStart && position + view.getIntrinsicHeight() >= maxShelfStart - && view.getTranslationY() < position) { - iconState.isLastExpandIcon = true; - iconState.customTransformHeight = NO_VALUE; - // Let's check if we're close enough to snap into the shelf - boolean forceInShelf = mMaxLayoutHeight - getIntrinsicHeight() - position - < getIntrinsicHeight(); - if (!forceInShelf) { - // We are overlapping the shelf but not enough, so the icon needs to be - // repositioned - iconState.customTransformHeight = (int) (mMaxLayoutHeight - - getIntrinsicHeight() - position); - } - } - } - } - private void updateIconPositioning(ExpandableView view, float iconTransitionAmount, - float fullTransitionAmount, float iconTransformDistance, boolean scrolling, boolean scrollingFast, boolean expandingAnimated, boolean isLastChild) { StatusBarIconView icon = view.getShelfIcon(); NotificationIconContainer.IconState iconState = getIconState(icon); if (iconState == null) { return; } - boolean forceInShelf = - iconState.isLastExpandIcon && !iconState.hasCustomTransformHeight(); boolean clampInShelf = iconTransitionAmount > 0.5f || isTargetClipped(view); float clampedAmount = clampInShelf ? 1.0f : 0.0f; if (iconTransitionAmount == clampedAmount) { - iconState.noAnimations = (scrollingFast || expandingAnimated) && !forceInShelf; - iconState.useFullTransitionAmount = iconState.noAnimations - || (!ICON_ANMATIONS_WHILE_SCROLLING && iconTransitionAmount == 0.0f - && scrolling); - iconState.useLinearTransitionAmount = !ICON_ANMATIONS_WHILE_SCROLLING - && iconTransitionAmount == 0.0f && !mAmbientState.isExpansionChanging(); - iconState.translateContent = mMaxLayoutHeight - getTranslationY() - - getIntrinsicHeight() > 0; - } - if (!forceInShelf && (scrollingFast || (expandingAnimated - && iconState.useFullTransitionAmount && !ViewState.isAnimatingY(icon)))) { + iconState.noAnimations = (scrollingFast || expandingAnimated) && !isLastChild; + } + if (!isLastChild + && (scrollingFast || (expandingAnimated && !ViewState.isAnimatingY(icon)))) { iconState.cancelAnimations(icon); - iconState.useFullTransitionAmount = true; iconState.noAnimations = true; } - if (iconState.hasCustomTransformHeight()) { - iconState.useFullTransitionAmount = true; - } - if (iconState.isLastExpandIcon) { - iconState.translateContent = false; - } float transitionAmount; if (mAmbientState.isHiddenAtAll() && !view.isInShelf()) { transitionAmount = mAmbientState.isFullyHidden() ? 1 : 0; - } else if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING - || iconState.useFullTransitionAmount - || iconState.useLinearTransitionAmount) { - transitionAmount = iconTransitionAmount; } else { transitionAmount = iconTransitionAmount; iconState.needsCannedAnimation = iconState.clampedAppearAmount != clampedAmount && !mNoAnimationsInThisFrame; } - iconState.iconAppearAmount = !USE_ANIMATIONS_WHEN_OPENING - || iconState.useFullTransitionAmount - ? fullTransitionAmount - : transitionAmount; iconState.clampedAppearAmount = clampedAmount; setIconTransformationAmount(view, transitionAmount, isLastChild); } @@ -706,8 +588,7 @@ public class NotificationShelf extends ActivatableNotificationView implements return endOfTarget >= getTranslationY() - mPaddingBetweenElements; } - private void setIconTransformationAmount(ExpandableView view, - float transitionAmount, + private void setIconTransformationAmount(ExpandableView view, float transitionAmount, boolean isLastChild) { if (!(view instanceof ExpandableNotificationRow)) { return; @@ -718,32 +599,30 @@ public class NotificationShelf extends ActivatableNotificationView implements if (iconState == null) { return; } - iconState.hidden = transitionAmount == 0.0f && !iconState.isAnimating(icon); - boolean isAppearing = row.isDrawingAppearAnimation() && !row.isInShelf(); - if (isAppearing) { - iconState.hidden = true; - iconState.iconAppearAmount = 0.0f; - } iconState.alpha = transitionAmount; + boolean isAppearing = row.isDrawingAppearAnimation() && !row.isInShelf(); + iconState.hidden = isAppearing + || (view instanceof ExpandableNotificationRow + && ((ExpandableNotificationRow) view).isLowPriority() + && mShelfIcons.hasMaxNumDot()) + || (transitionAmount == 0.0f && !iconState.isAnimating(icon)) + || row.isAboveShelf() + || row.showingPulsing() + || (!row.isInShelf() && isLastChild) + || row.getTranslationZ() > mAmbientState.getBaseZHeight(); + iconState.iconAppearAmount = iconState.hidden? 0f : transitionAmount; + // Fade in icons at shelf start // This is important for conversation icons, which are badged and need x reset iconState.xTranslation = mShelfIcons.getActualPaddingStart(); - boolean stayingInShelf = row.isInShelf() && !row.isTransformingIntoShelf(); + final boolean stayingInShelf = row.isInShelf() && !row.isTransformingIntoShelf(); if (stayingInShelf) { iconState.iconAppearAmount = 1.0f; iconState.alpha = 1.0f; - iconState.scaleX = 1.0f; - iconState.scaleY = 1.0f; iconState.hidden = false; } - if (row.isAboveShelf() - || row.showingPulsing() - || (!row.isInShelf() && (isLastChild && row.areGutsExposed() - || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) { - iconState.hidden = true; - } int backgroundColor = getBackgroundColorWithoutTint(); int shelfColor = icon.getContrastedStaticDrawableColor(backgroundColor); if (row.isShowingIcon() && shelfColor != StatusBarIconView.NO_COLOR) { @@ -819,42 +698,6 @@ public class NotificationShelf extends ActivatableNotificationView implements return ret; } - private void setOpenedAmount(float openedAmount) { - mNoAnimationsInThisFrame = openedAmount == 1.0f && mOpenedAmount == 0.0f; - mOpenedAmount = openedAmount; - if (!mAmbientState.isPanelFullWidth() || mAmbientState.isDozing()) { - // We don't do a transformation at all, lets just assume we are fully opened - openedAmount = 1.0f; - } - int start = mRelativeOffset; - if (isLayoutRtl()) { - start = getWidth() - start - mCollapsedIcons.getWidth(); - } - int width = (int) NotificationUtils.interpolate( - start + mCollapsedIcons.getFinalTranslationX(), - mShelfIcons.getWidth(), - FAST_OUT_SLOW_IN_REVERSE.getInterpolation(openedAmount)); - mShelfIcons.setActualLayoutWidth(width); - boolean hasOverflow = mCollapsedIcons.hasOverflow(); - int collapsedPadding = mCollapsedIcons.getPaddingEnd(); - if (!hasOverflow) { - // we have to ensure that adding the low priority notification won't lead to an - // overflow - collapsedPadding -= mCollapsedIcons.getNoOverflowExtraPadding(); - } else { - // Partial overflow padding will fill enough space to add extra dots - collapsedPadding -= mCollapsedIcons.getPartialOverflowExtraPadding(); - } - float padding = NotificationUtils.interpolate(collapsedPadding, - mShelfIcons.getPaddingEnd(), - openedAmount); - mShelfIcons.setActualPaddingEnd(padding); - float paddingStart = NotificationUtils.interpolate(start, - mShelfIcons.getPaddingStart(), openedAmount); - mShelfIcons.setActualPaddingStart(paddingStart); - mShelfIcons.setOpenedAmount(openedAmount); - } - public void setMaxLayoutHeight(int maxLayoutHeight) { mMaxLayoutHeight = maxLayoutHeight; } @@ -947,7 +790,6 @@ public class NotificationShelf extends ActivatableNotificationView implements } private class ShelfState extends ExpandableViewState { - private float openedAmount; private boolean hasItemsInStableShelf; @Override @@ -957,7 +799,6 @@ public class NotificationShelf extends ActivatableNotificationView implements } super.applyToView(view); - setOpenedAmount(openedAmount); updateAppearance(); setHasItemsInStableShelf(hasItemsInStableShelf); mShelfIcons.setAnimationsEnabled(mAnimationsEnabled); @@ -970,7 +811,6 @@ public class NotificationShelf extends ActivatableNotificationView implements } super.animateTo(child, properties); - setOpenedAmount(openedAmount); updateAppearance(); setHasItemsInStableShelf(hasItemsInStableShelf); mShelfIcons.setAnimationsEnabled(mAnimationsEnabled); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java index d08f9736adf6..85a1aed68559 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java @@ -146,17 +146,19 @@ public class ActivityLaunchAnimator { private final ExpandableNotificationRow mSourceNotification; private final ExpandAnimationParameters mParams; private final Rect mWindowCrop = new Rect(); - private final float mNotificationCornerRadius; - private float mCornerRadius; private boolean mIsFullScreenLaunch = true; private final SyncRtSurfaceTransactionApplier mSyncRtTransactionApplier; - public AnimationRunner(ExpandableNotificationRow sourceNofitication) { - mSourceNotification = sourceNofitication; + private final float mNotificationStartTopCornerRadius; + private final float mNotificationStartBottomCornerRadius; + + AnimationRunner(ExpandableNotificationRow sourceNotification) { + mSourceNotification = sourceNotification; mParams = new ExpandAnimationParameters(); mSyncRtTransactionApplier = new SyncRtSurfaceTransactionApplier(mSourceNotification); - mNotificationCornerRadius = Math.max(mSourceNotification.getCurrentTopRoundness(), - mSourceNotification.getCurrentBottomRoundness()); + mNotificationStartTopCornerRadius = mSourceNotification.getCurrentBackgroundRadiusTop(); + mNotificationStartBottomCornerRadius = + mSourceNotification.getCurrentBackgroundRadiusBottom(); } @Override @@ -224,7 +226,10 @@ public class ActivityLaunchAnimator { + notificationHeight, primary.position.y + primary.sourceContainerBounds.bottom, progress); - mCornerRadius = MathUtils.lerp(mNotificationCornerRadius, + mParams.topCornerRadius = MathUtils.lerp(mNotificationStartTopCornerRadius, + mWindowCornerRadius, progress); + mParams.bottomCornerRadius = MathUtils.lerp( + mNotificationStartBottomCornerRadius, mWindowCornerRadius, progress); applyParamsToWindow(primary); applyParamsToNotification(mParams); @@ -309,12 +314,13 @@ public class ActivityLaunchAnimator { Matrix m = new Matrix(); m.postTranslate(0, (float) (mParams.top - app.position.y)); mWindowCrop.set(mParams.left, 0, mParams.right, mParams.getHeight()); + float cornerRadius = Math.min(mParams.topCornerRadius, mParams.bottomCornerRadius); SurfaceParams params = new SurfaceParams.Builder(app.leash) .withAlpha(1f) .withMatrix(m) .withWindowCrop(mWindowCrop) .withLayer(app.prefixOrderIndex) - .withCornerRadius(mCornerRadius) + .withCornerRadius(cornerRadius) .withVisibility(true) .build(); mSyncRtTransactionApplier.scheduleApply(params); @@ -339,6 +345,8 @@ public class ActivityLaunchAnimator { int bottom; int startClipTopAmount; int parentStartClipTopAmount; + float topCornerRadius; + float bottomCornerRadius; public ExpandAnimationParameters() { } @@ -389,6 +397,14 @@ public class ActivityLaunchAnimator { public float getStartTranslationZ() { return startTranslationZ; } + + public float getTopCornerRadius() { + return topCornerRadius; + } + + public float getBottomCornerRadius() { + return bottomCornerRadius; + } } public interface Callback { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt index 004cf9968a77..b0d41f155713 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt @@ -218,13 +218,18 @@ class ConversationNotificationManager @Inject constructor( }) } + private fun ConversationState.shouldIncrementUnread(newBuilder: Notification.Builder) = + if (notification.flags and Notification.FLAG_ONLY_ALERT_ONCE != 0) { + false + } else { + val oldBuilder = Notification.Builder.recoverBuilder(context, notification) + Notification.areStyledNotificationsVisiblyDifferent(oldBuilder, newBuilder) + } + fun getUnreadCount(entry: NotificationEntry, recoveredBuilder: Notification.Builder): Int = states.compute(entry.key) { _, state -> val newCount = state?.run { - val old = Notification.Builder.recoverBuilder(context, notification) - val increment = Notification - .areStyledNotificationsVisiblyDifferent(old, recoveredBuilder) - if (increment) unreadCount + 1 else unreadCount + if (shouldIncrementUnread(recoveredBuilder)) unreadCount + 1 else unreadCount } ?: 1 ConversationState(newCount, entry.sbn.notification) }!!.unreadCount diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java index 18806effc545..5a3f48cec290 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java @@ -99,17 +99,11 @@ public class HighPriorityProvider { private boolean hasHighPriorityCharacteristics(NotificationEntry entry) { return !hasUserSetImportance(entry) - && (isImportantOngoing(entry) - || entry.getSbn().getNotification().hasMediaSession() + && (entry.getSbn().getNotification().hasMediaSession() || isPeopleNotification(entry) || isMessagingStyle(entry)); } - private boolean isImportantOngoing(NotificationEntry entry) { - return entry.getSbn().getNotification().isForegroundService() - && entry.getRanking().getImportance() >= NotificationManager.IMPORTANCE_LOW; - } - private boolean isMessagingStyle(NotificationEntry entry) { return Notification.MessagingStyle.class.equals( entry.getSbn().getNotification().getNotificationStyle()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 31d052d75998..18e5ead7fbb8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -883,8 +883,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } private void applyBackgroundRoundness(float topRadius, float bottomRadius) { - mBackgroundDimmed.setRoundness(topRadius, bottomRadius); - mBackgroundNormal.setRoundness(topRadius, bottomRadius); + mBackgroundDimmed.setRadius(topRadius, bottomRadius); + mBackgroundNormal.setRadius(topRadius, bottomRadius); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 0f23b770aacd..046fbd5b616b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -166,7 +166,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private int mMaxSmallHeightLarge; private int mMaxSmallHeightMedia; private int mMaxExpandedHeight; - private int mMaxCallHeight; private int mIncreasedPaddingBetweenElements; private int mNotificationLaunchHeight; private boolean mMustStayOnScreen; @@ -347,6 +346,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private SystemNotificationAsyncTask mSystemNotificationAsyncTask = new SystemNotificationAsyncTask(); + private float mTopRoundnessDuringExpandAnimation; + private float mBottomRoundnessDuringExpandAnimation; + /** * Returns whether the given {@code statusBarNotification} is a system notification. * <b>Note</b>, this should be run in the background thread if possible as it makes multiple IPC @@ -687,7 +689,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // them a headerless design, then remove this hack. smallHeight = mMaxSmallHeightLarge; } else if (isCallLayout) { - smallHeight = mMaxCallHeight; + smallHeight = mMaxExpandedHeight; } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) { smallHeight = mMaxSmallHeightLarge; } else { @@ -1621,8 +1623,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView R.dimen.notification_min_height_media); mMaxExpandedHeight = NotificationUtils.getFontScaledHeight(mContext, R.dimen.notification_max_height); - mMaxCallHeight = NotificationUtils.getFontScaledHeight(mContext, - R.dimen.call_notification_full_height); mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext, R.dimen.notification_max_heads_up_height_legacy); mMaxHeadsUpHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext, @@ -2012,6 +2012,24 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return false; } + @Override + public float getCurrentTopRoundness() { + if (mExpandAnimationRunning) { + return mTopRoundnessDuringExpandAnimation; + } + + return super.getCurrentTopRoundness(); + } + + @Override + public float getCurrentBottomRoundness() { + if (mExpandAnimationRunning) { + return mBottomRoundnessDuringExpandAnimation; + } + + return super.getCurrentBottomRoundness(); + } + public void applyExpandAnimationParams(ExpandAnimationParameters params) { if (params == null) { return; @@ -2027,17 +2045,22 @@ public class ExpandableNotificationRow extends ActivatableNotificationView int top = params.getTop(); float interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(params.getProgress()); int startClipTopAmount = params.getStartClipTopAmount(); + int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, interpolation); if (mNotificationParent != null) { float parentY = mNotificationParent.getTranslationY(); top -= parentY; mNotificationParent.setTranslationZ(translationZ); + + // When the expanding notification is below its parent, the parent must be clipped + // exactly how it was clipped before the animation. When the expanding notification is + // on or above its parent (top <= 0), then the parent must be clipped exactly 'top' + // pixels to show the expanding notification, while still taking the decreasing + // notification clipTopAmount into consideration, so 'top + clipTopAmount'. int parentStartClipTopAmount = params.getParentStartClipTopAmount(); - if (startClipTopAmount != 0) { - int clipTopAmount = (int) MathUtils.lerp(parentStartClipTopAmount, - parentStartClipTopAmount - startClipTopAmount, - interpolation); - mNotificationParent.setClipTopAmount(clipTopAmount); - } + int parentClipTopAmount = Math.min(parentStartClipTopAmount, + top + clipTopAmount); + mNotificationParent.setClipTopAmount(parentClipTopAmount); + mNotificationParent.setExtraWidthForClipping(extraWidthForClipping); float clipBottom = Math.max(params.getBottom(), parentY + mNotificationParent.getActualHeight() @@ -2046,12 +2069,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView int minimumHeightForClipping = (int) (clipBottom - clipTop); mNotificationParent.setMinimumHeightForClipping(minimumHeightForClipping); } else if (startClipTopAmount != 0) { - int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, interpolation); setClipTopAmount(clipTopAmount); } setTranslationY(top); setActualHeight(params.getHeight()); + mTopRoundnessDuringExpandAnimation = params.getTopCornerRadius() / mOutlineRadius; + mBottomRoundnessDuringExpandAnimation = params.getBottomCornerRadius() / mOutlineRadius; + invalidateOutline(); + mBackgroundNormal.setExpandAnimationParams(params); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java index 85f556fa733c..3728388f63b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java @@ -27,7 +27,6 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; -import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; @@ -83,8 +82,8 @@ public abstract class ExpandableOutlineView extends ExpandableView { private final ViewOutlineProvider mProvider = new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { - if (!mCustomOutline && mCurrentTopRoundness == 0.0f - && mCurrentBottomRoundness == 0.0f && !mAlwaysRoundBothCorners + if (!mCustomOutline && getCurrentTopRoundness() == 0.0f + && getCurrentBottomRoundness() == 0.0f && !mAlwaysRoundBothCorners && !mTopAmountRounded) { int translation = mShouldTranslateContents ? (int) getTranslation() : 0; int left = Math.max(translation, 0); @@ -135,10 +134,12 @@ public abstract class ExpandableOutlineView extends ExpandableView { ? mOutlineRadius : getCurrentBackgroundRadiusBottom(); if (topRoundness + bottomRoundness > height) { float overShoot = topRoundness + bottomRoundness - height; - topRoundness -= overShoot * mCurrentTopRoundness - / (mCurrentTopRoundness + mCurrentBottomRoundness); - bottomRoundness -= overShoot * mCurrentBottomRoundness - / (mCurrentTopRoundness + mCurrentBottomRoundness); + float currentTopRoundness = getCurrentTopRoundness(); + float currentBottomRoundness = getCurrentBottomRoundness(); + topRoundness -= overShoot * currentTopRoundness + / (currentTopRoundness + currentBottomRoundness); + bottomRoundness -= overShoot * currentBottomRoundness + / (currentTopRoundness + currentBottomRoundness); } getRoundedRectPath(left, top, right, bottom, topRoundness, bottomRoundness, mTmpPath); return mTmpPath; @@ -267,7 +268,7 @@ public abstract class ExpandableOutlineView extends ExpandableView { if (mTopAmountRounded) { return mOutlineRadius; } - return mCurrentTopRoundness * mOutlineRadius; + return getCurrentTopRoundness() * mOutlineRadius; } public float getCurrentTopRoundness() { @@ -278,8 +279,8 @@ public abstract class ExpandableOutlineView extends ExpandableView { return mCurrentBottomRoundness; } - protected float getCurrentBackgroundRadiusBottom() { - return mCurrentBottomRoundness * mOutlineRadius; + public float getCurrentBackgroundRadiusBottom() { + return getCurrentBottomRoundness() * mOutlineRadius; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index ba03d01b20b0..73e080423d40 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -69,7 +69,6 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { private float mContentTranslation; protected boolean mLastInSection; protected boolean mFirstInSection; - boolean mIsBeingSwiped; public ExpandableView(Context context, AttributeSet attrs) { super(context, attrs); @@ -174,14 +173,6 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { return false; } - public void setIsBeingSwiped(boolean swiped) { - mIsBeingSwiped = swiped; - } - - public boolean isBeingSwiped() { - return mIsBeingSwiped; - } - public boolean isHeadsUpAnimatingAway() { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java index 62d596b60a89..95885633a3e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java @@ -224,10 +224,9 @@ public class NotificationBackgroundView extends View { } /** - * Sets the current top and bottom roundness amounts for this background, between 0.0 (not - * rounded) and 1.0 (maximally rounded). + * Sets the current top and bottom radius for this background. */ - public void setRoundness(float topRoundness, float bottomRoundness) { + public void setRadius(float topRoundness, float bottomRoundness) { if (topRoundness == mCornerRadii[0] && bottomRoundness == mCornerRadii[4]) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCallTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCallTemplateViewWrapper.kt index 4541ebf4c4f2..12e94cbc1ab9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCallTemplateViewWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCallTemplateViewWrapper.kt @@ -34,7 +34,7 @@ class NotificationCallTemplateViewWrapper constructor( ) : NotificationTemplateViewWrapper(ctx, view, row) { private val minHeightWithActions: Int = - NotificationUtils.getFontScaledHeight(ctx, R.dimen.call_notification_full_height) + NotificationUtils.getFontScaledHeight(ctx, R.dimen.notification_max_height) private val callLayout: CallLayout = view as CallLayout private lateinit var conversationIconView: CachingIconView 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 d8ee102064e1..2b194ba15816 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 @@ -34,7 +34,6 @@ import android.widget.RemoteViews; import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.widget.CachingIconView; import com.android.internal.widget.NotificationExpandButton; import com.android.systemui.R; import com.android.systemui.statusbar.CrossFadeHelper; @@ -638,10 +637,6 @@ public class NotificationChildrenContainer extends ViewGroup { childState.location = parentState.location; childState.inShelf = parentState.inShelf; yPosition += intrinsicHeight; - if (child.isExpandAnimationRunning()) { - launchTransitionCompensation = -ambientState.getExpandAnimationTopChange(); - } - } if (mOverflowNumber != null) { ExpandableNotificationRow overflowView = mAttachedChildren.get(Math.min( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java index 45f5b3136b9b..b1ac12e84fb3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.stack; import android.content.res.Resources; import android.util.MathUtils; +import android.view.View; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; @@ -47,6 +48,10 @@ public class NotificationRoundnessManager { private ExpandableNotificationRow mTrackedHeadsUp; private float mAppearFraction; + private ExpandableView mSwipedView = null; + private ExpandableView mViewBeforeSwipedView = null; + private ExpandableView mViewAfterSwipedView = null; + @Inject NotificationRoundnessManager( KeyguardBypassController keyguardBypassController, @@ -68,6 +73,11 @@ public class NotificationRoundnessManager { boolean updateViewWithoutCallback(ExpandableView view, boolean animate) { + if (view == null + || view == mViewBeforeSwipedView + || view == mViewAfterSwipedView) { + return false; + } float topRoundness = getRoundness(view, true /* top */); float bottomRoundness = getRoundness(view, false /* top */); boolean topChanged = view.setTopRoundness(topRoundness, animate); @@ -105,9 +115,60 @@ public class NotificationRoundnessManager { return false; } + void setViewsAffectedBySwipe( + ExpandableView viewBefore, + ExpandableView viewSwiped, + ExpandableView viewAfter, + boolean cornerAnimationsEnabled) { + if (!cornerAnimationsEnabled) { + return; + } + final boolean animate = true; + + ExpandableView oldViewBefore = mViewBeforeSwipedView; + mViewBeforeSwipedView = viewBefore; + if (oldViewBefore != null) { + final float bottomRoundness = getRoundness(oldViewBefore, false /* top */); + oldViewBefore.setBottomRoundness(bottomRoundness, animate); + } + if (viewBefore != null) { + viewBefore.setBottomRoundness(1f, animate); + } + + ExpandableView oldSwipedview = mSwipedView; + mSwipedView = viewSwiped; + if (oldSwipedview != null) { + final float bottomRoundness = getRoundness(oldSwipedview, false /* top */); + final float topRoundness = getRoundness(oldSwipedview, true /* top */); + oldSwipedview.setTopRoundness(topRoundness, animate); + oldSwipedview.setBottomRoundness(bottomRoundness, animate); + } + if (viewSwiped != null) { + viewSwiped.setTopRoundness(1f, animate); + viewSwiped.setBottomRoundness(1f, animate); + } + + ExpandableView oldViewAfter = mViewAfterSwipedView; + mViewAfterSwipedView = viewAfter; + if (oldViewAfter != null) { + final float topRoundness = getRoundness(oldViewAfter, true /* top */); + oldViewAfter.setTopRoundness(topRoundness, animate); + } + if (viewAfter != null) { + viewAfter.setTopRoundness(1f, animate); + } + } + private float getRoundness(ExpandableView view, boolean top) { + if (view == null) { + return 0f; + } + if (view == mViewBeforeSwipedView + || view == mSwipedView + || view == mViewAfterSwipedView) { + return 1f; + } if ((view.isPinned() - || view.isBeingSwiped() || (view.isHeadsUpAnimatingAway()) && !mExpanded)) { return 1.0f; } 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 6c8cdf67d974..b06f7d25db16 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 @@ -318,9 +318,6 @@ class NotificationSectionsManager @Inject internal constructor( (child == null || row != null && nextBucket != row.entry.bucket) if (isSectionBoundary && showHeaders) { when (nextBucket) { - BUCKET_HEADS_UP -> incomingState?.targetPosition = i + 1 - BUCKET_PEOPLE -> peopleState?.targetPosition = i + 1 - BUCKET_ALERTING -> alertingState?.targetPosition = i + 1 BUCKET_SILENT -> gentleState?.targetPosition = i + 1 } } 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 417ff5e9aed0..970efd5cbfe2 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 @@ -1025,8 +1025,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable boolean clip = clipStart > start && clipStart < end || clipEnd >= start && clipEnd <= end; clip &= !(first && mScrollAdapter.isScrolledToTop()); - child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0) - : ExpandableView.NO_ROUNDNESS); + child.setDistanceToTopRoundness(ExpandableView.NO_ROUNDNESS); first = false; } } @@ -2292,9 +2291,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable ExpandableView child = (ExpandableView) getChildAt(i); if (child.getVisibility() != View.GONE && !(child instanceof StackScrollerDecorView) - && child != mShelf - && (mSwipeHelper.getSwipedView() != child - || !child.getResources().getBoolean(R.bool.flag_notif_updates))) { + && child != mShelf) { children.add(child); } } @@ -4993,28 +4990,48 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mSwipedOutViews.add(v); } - void onSwipeBegin(View v) { - if (v instanceof ExpandableView) { - ExpandableView ev = (ExpandableView) v; - ev.setIsBeingSwiped(true); - mController.getNoticationRoundessManager() - .updateViewWithoutCallback(ev, true /* animate */); + void onSwipeBegin(View viewSwiped) { + if (!(viewSwiped instanceof ExpandableNotificationRow)) { + return; } - requestDisallowInterceptTouchEvent(true); + final int indexOfSwipedView = indexOfChild(viewSwiped); + if (indexOfSwipedView < 0) { + return; + } + mSectionsManager.updateFirstAndLastViewsForAllSections( + mSections, getChildrenWithBackground()); + View viewBefore = null; + if (indexOfSwipedView > 0) { + viewBefore = getChildAt(indexOfSwipedView - 1); + if (mSectionsManager.beginsSection(viewSwiped, viewBefore)) { + viewBefore = null; + } + } + View viewAfter = null; + if (indexOfSwipedView < getChildCount()) { + viewAfter = getChildAt(indexOfSwipedView + 1); + if (mSectionsManager.beginsSection(viewAfter, viewSwiped)) { + viewAfter = null; + } + } + mController.getNoticationRoundessManager() + .setViewsAffectedBySwipe((ExpandableView) viewBefore, + (ExpandableView) viewSwiped, + (ExpandableView) viewAfter, + getResources().getBoolean(R.bool.flag_notif_updates)); + updateFirstAndLastBackgroundViews(); + requestDisallowInterceptTouchEvent(true); updateContinuousShadowDrawing(); updateContinuousBackgroundDrawing(); requestChildrenUpdate(); } - void onSwipeEnd(View v) { - if (v instanceof ExpandableView) { - ExpandableView ev = (ExpandableView) v; - ev.setIsBeingSwiped(false); - mController.getNoticationRoundessManager() - .updateViewWithoutCallback(ev, true /* animate */); - } + void onSwipeEnd() { updateFirstAndLastBackgroundViews(); + mController.getNoticationRoundessManager() + .setViewsAffectedBySwipe(null, null, null, + getResources().getBoolean(R.bool.flag_notif_updates)); } void setTopHeadsUpEntry(NotificationEntry topEntry) { 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 399702869d70..7baad1cc265e 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 @@ -399,7 +399,7 @@ public class NotificationStackScrollLayoutController { if (mView.getDismissAllInProgress()) { return; } - mView.onSwipeEnd(view); + mView.onSwipeEnd(); if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) view; if (row.isHeadsUp()) { @@ -459,7 +459,7 @@ public class NotificationStackScrollLayoutController { @Override public void onChildSnappedBack(View animView, float targetLeft) { - mView.onSwipeEnd(animView); + mView.onSwipeEnd(); if (animView instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) animView; if (row.isPinned() && !canChildBeDismissed(row) 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 5d2203b57991..d7a98bdf2715 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 @@ -28,14 +28,12 @@ import android.view.ViewGroup; import com.android.systemui.R; import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.NotificationShelf; -import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.row.FooterView; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; /** @@ -156,7 +154,7 @@ public class StackScrollAlgorithm { private void updateClipping(StackScrollAlgorithmState algorithmState, AmbientState ambientState) { float drawStart = !ambientState.isOnKeyguard() ? ambientState.getTopPadding() - + ambientState.getStackTranslation() + ambientState.getExpandAnimationTopChange() + + ambientState.getStackTranslation() : 0; float clipStart = 0; int childCount = algorithmState.visibleChildren.size(); @@ -329,9 +327,6 @@ public class StackScrollAlgorithm { childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA; float inset = ambientState.getTopPadding() + ambientState.getStackTranslation() + ambientState.getSectionPadding(); - if (i <= algorithmState.getIndexOfExpandingNotification()) { - inset += ambientState.getExpandAnimationTopChange(); - } if (child.mustStayOnScreen() && childViewState.yTranslation >= 0) { // Even if we're not scrolled away we're in view and we're also not in the // shelf. We can relax the constraints and let us scroll off the top! 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 85d8df8e6057..c23f1ad6f9c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -148,6 +148,11 @@ public class DozeParameters implements TunerService.Tunable, return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold); } + public int getQuickPickupAodDuration() { + return getInt("doze.gesture.quickpickup.duration", + R.integer.doze_quick_pickup_aod_duration); + } + /** * For how long a wallpaper can be visible in AoD before it fades aways. * @return duration in millis. @@ -175,6 +180,10 @@ public class DozeParameters implements TunerService.Tunable, return mDozeAlwaysOn && !mBatteryController.isAodPowerSave(); } + public boolean isQuickPickupEnabled() { + return mAmbientDisplayConfiguration.quickPickupSensorEnabled(UserHandle.USER_CURRENT); + } + /** * Some screens need to be completely black before changing the display power mode, * unexpected behavior might happen if this parameter isn't respected. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index 9561851ab28b..6b144c652c56 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -28,6 +28,7 @@ import android.graphics.Rect; import android.graphics.drawable.Icon; import android.util.AttributeSet; import android.util.Property; +import android.view.ContextThemeWrapper; import android.view.View; import android.view.animation.Interpolator; @@ -35,6 +36,7 @@ import androidx.collection.ArrayMap; import com.android.internal.statusbar.StatusBarIcon; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.settingslib.Utils; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.statusbar.AlphaOptimizedFrameLayout; @@ -155,7 +157,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { private int mCannedAnimationStartIndex = -1; private int mSpeedBumpIndex = -1; private int mIconSize; - private float mOpenedAmount = 0.0f; private boolean mDisallowNextAnimation; private boolean mAnimationsEnabled = true; private ArrayMap<String, ArrayList<StatusBarIcon>> mReplacingIcons; @@ -169,6 +170,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { private Rect mIsolatedIconLocation; private int[] mAbsolutePosition = new int[2]; private View mIsolatedIconForAnimation; + private int mThemedTextColorPrimary; public NotificationIconContainer(Context context, AttributeSet attrs) { super(context, attrs); @@ -180,6 +182,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding); mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius); mStaticDotDiameter = 2 * mStaticDotRadius; + final Context themedContext = new ContextThemeWrapper(getContext(), + com.android.internal.R.style.Theme_DeviceDefault_DayNight); + mThemedTextColorPrimary = Utils.getColorAttr(themedContext, + com.android.internal.R.attr.textColorPrimary).getDefaultColor(); } @Override @@ -349,6 +355,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { } } + public boolean hasMaxNumDot() { + return mNumDots >= MAX_DOTS; + } + private boolean areAnimationsEnabled(StatusBarIconView icon) { return mAnimationsEnabled || icon == mIsolatedIcon; } @@ -391,7 +401,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { float overflowStart = getMaxOverflowStart(); mVisualOverflowStart = 0; mFirstVisibleIconState = null; - boolean hasAmbient = mSpeedBumpIndex != -1 && mSpeedBumpIndex < getChildCount(); for (int i = 0; i < childCount; i++) { View view = getChildAt(i); IconState iconState = mIconStates.get(view); @@ -410,10 +419,9 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { float drawingScale = mOnLockScreen && view instanceof StatusBarIconView ? ((StatusBarIconView) view).getIconScaleIncreased() : 1f; - if (mOpenedAmount != 0.0f) { - noOverflowAfter = noOverflowAfter && !hasAmbient && !forceOverflow; - } - iconState.visibleState = StatusBarIconView.STATE_ICON; + iconState.visibleState = iconState.hidden + ? StatusBarIconView.STATE_HIDDEN + : StatusBarIconView.STATE_ICON; boolean isOverflowing = (translationX > (noOverflowAfter ? layoutEnd - mIconSize @@ -598,10 +606,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { mSpeedBumpIndex = speedBumpIndex; } - public void setOpenedAmount(float expandAmount) { - mOpenedAmount = expandAmount; - } - public boolean hasOverflow() { return mNumDots > 0; } @@ -706,13 +710,8 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { public boolean justAdded = true; private boolean justReplaced; public boolean needsCannedAnimation; - public boolean useFullTransitionAmount; - public boolean useLinearTransitionAmount; - public boolean translateContent; public int iconColor = StatusBarIconView.NO_COLOR; public boolean noAnimations; - public boolean isLastExpandIcon; - public int customTransformHeight = NO_VALUE; private final View mView; private final Consumer<Property> mCannedAnimationEndListener; @@ -734,8 +733,15 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { StatusBarIconView icon = (StatusBarIconView) view; boolean animate = false; AnimationProperties animationProperties = null; - boolean animationsAllowed = areAnimationsEnabled(icon) && !mDisallowNextAnimation - && !noAnimations; + final boolean isLowPriorityIconChange = + (visibleState == StatusBarIconView.STATE_HIDDEN + && icon.getVisibleState() == StatusBarIconView.STATE_DOT) + || (visibleState == StatusBarIconView.STATE_DOT + && icon.getVisibleState() == StatusBarIconView.STATE_HIDDEN); + final boolean animationsAllowed = areAnimationsEnabled(icon) + && !mDisallowNextAnimation + && !noAnimations + && !isLowPriorityIconChange; if (animationsAllowed) { if (justAdded || justReplaced) { super.applyToView(icon); @@ -807,7 +813,8 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { } } icon.setVisibleState(visibleState, animationsAllowed); - icon.setIconColor(iconColor, needsCannedAnimation && animationsAllowed); + icon.setIconColor(mThemedTextColorPrimary, + needsCannedAnimation && animationsAllowed); if (animate) { animateTo(icon, animationProperties); } else { @@ -822,10 +829,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { needsCannedAnimation = false; } - public boolean hasCustomTransformHeight() { - return isLastExpandIcon && customTransformHeight != NO_VALUE; - } - @Override public void initFrom(View view) { super.initFrom(view); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 19b98953325f..ca6e53d2ec04 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -439,7 +439,6 @@ public class NotificationPanelViewController extends PanelViewController { private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); private boolean mUserSetupComplete; private int mQsNotificationTopPadding; - private float mExpandOffset; private boolean mHideIconsDuringNotificationLaunch = true; private int mStackScrollerMeasuringPass; private ArrayList<Consumer<ExpandableNotificationRow>> @@ -576,8 +575,8 @@ public class NotificationPanelViewController extends PanelViewController { FeatureFlags featureFlags) { super(view, falsingManager, dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, vibratorHelper, - latencyTracker, flingAnimationUtilsBuilder.get(), statusBarTouchableRegionManager, - ambientState); + statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(), + statusBarTouchableRegionManager, ambientState); mView = view; mMetricsLogger = metricsLogger; mActivityManager = activityManager; @@ -1349,7 +1348,6 @@ public class NotificationPanelViewController extends PanelViewController { super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing); } - private boolean onQsIntercept(MotionEvent event) { int pointerIndex = event.findPointerIndex(mTrackingPointer); if (pointerIndex < 0) { @@ -2444,8 +2442,7 @@ public class NotificationPanelViewController extends PanelViewController { } startHeight = -mQs.getQsMinExpansionHeight(); } - float translation = MathUtils.lerp(startHeight, 0, Math.min(1.0f, appearAmount)) - + mExpandOffset; + float translation = MathUtils.lerp(startHeight, 0, Math.min(1.0f, appearAmount)); return Math.min(0, translation); } @@ -3185,16 +3182,16 @@ public class NotificationPanelViewController extends PanelViewController { } public void applyExpandAnimationParams(ExpandAnimationParameters params) { - mExpandOffset = params != null ? params.getTopChange() : 0; - updateQsExpansion(); - if (params != null) { - boolean hideIcons = params.getProgress( - ActivityLaunchAnimator.ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f; - if (hideIcons != mHideIconsDuringNotificationLaunch) { - mHideIconsDuringNotificationLaunch = hideIcons; - if (!hideIcons) { - mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */); - } + if (params == null) { + return; + } + + boolean hideIcons = params.getProgress( + ActivityLaunchAnimator.ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f; + if (hideIcons != mHideIconsDuringNotificationLaunch) { + mHideIconsDuringNotificationLaunch = hideIcons; + if (!hideIcons) { + mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java index 50c8e2e0d710..66df936dd556 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java @@ -64,7 +64,7 @@ public class NotificationTapHelper { mTrackTouch = event.getY() <= maxTouchableHeight; break; case MotionEvent.ACTION_MOVE: - if (mTrackTouch && mFalsingManager.isFalseTap(false)) { + if (mTrackTouch && mFalsingManager.isFalseTap(false, 0)) { makeInactive(); mTrackTouch = false; } @@ -78,10 +78,10 @@ public class NotificationTapHelper { // 1) See if we have confidence that we can activate after a single tap. // 2) Else, see if it looks like a tap at all and check for a double-tap. - if (!mFalsingManager.isFalseTap(true)) { + if (!mFalsingManager.isFalseTap(true, 0)) { makeInactive(); return mDoubleTapListener.onDoubleTap(); - } else if (!mFalsingManager.isFalseTap(false)) { + } else if (!mFalsingManager.isFalseTap(false, 0)) { if (mSlideBackListener != null && mSlideBackListener.onSlideBack()) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java index 0c9ed661925c..1cb0be0efc90 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java @@ -89,30 +89,22 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout @Override protected void dispatchDraw(Canvas canvas) { - // Invert the order of the scroll view and user switcher such that the notifications receive - // touches first but the panel gets drawn above. mDrawingOrderedChildren.clear(); mLayoutDrawingOrder.clear(); if (mKeyguardStatusBar.getVisibility() == View.VISIBLE) { mDrawingOrderedChildren.add(mKeyguardStatusBar); mLayoutDrawingOrder.add(mKeyguardStatusBar); } - if (mStackScroller.getVisibility() == View.VISIBLE) { - mDrawingOrderedChildren.add(mStackScroller); - mLayoutDrawingOrder.add(mStackScroller); - } if (mQsFrame.getVisibility() == View.VISIBLE) { mDrawingOrderedChildren.add(mQsFrame); mLayoutDrawingOrder.add(mQsFrame); } - - if (mHasViewsAboveShelf) { - // StackScroller needs to be on top - mDrawingOrderedChildren.remove(mStackScroller); + if (mStackScroller.getVisibility() == View.VISIBLE) { mDrawingOrderedChildren.add(mStackScroller); + mLayoutDrawingOrder.add(mStackScroller); } - // Let's now find the order that the view has when drawing regulary by sorting + // Let's now find the order that the view has when drawing regularly by sorting mLayoutDrawingOrder.sort(mIndexComparator); super.dispatchDraw(canvas); } 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 b6ed3e50ed7e..3ac69378d7d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -167,6 +167,7 @@ public abstract class PanelViewController { private boolean mIgnoreXTouchSlop; private boolean mExpandLatencyTracking; private final PanelView mView; + private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; protected final Resources mResources; protected final KeyguardStateController mKeyguardStateController; protected final SysuiStatusBarStateController mStatusBarStateController; @@ -235,12 +236,14 @@ public abstract class PanelViewController { FalsingManager falsingManager, DozeLog dozeLog, KeyguardStateController keyguardStateController, SysuiStatusBarStateController statusBarStateController, VibratorHelper vibratorHelper, + StatusBarKeyguardViewManager statusBarKeyguardViewManager, LatencyTracker latencyTracker, FlingAnimationUtils.Builder flingAnimationUtilsBuilder, StatusBarTouchableRegionManager statusBarTouchableRegionManager, AmbientState ambientState) { mAmbientState = ambientState; mView = view; + mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { @@ -1391,8 +1394,13 @@ public abstract class PanelViewController { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: - addMovement(event); - endMotionEvent(event, x, y, false /* forceCancel */); + if (mStatusBarKeyguardViewManager.isBouncerShowing() + && mFalsingManager.isFalseTap(true, 0.5)) { + endMotionEvent(event, x, y, true /* forceCancel */); + } else { + addMovement(event); + endMotionEvent(event, x, y, false /* forceCancel */); + } InteractionJankMonitor monitor = InteractionJankMonitor.getInstance(); if (event.getActionMasked() == MotionEvent.ACTION_UP) { monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); 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 48c97a2fd79c..9b8b7160c95c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -140,11 +140,13 @@ public enum ScrimState { @Override public void prepare(ScrimState previousState) { final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn(); + final boolean quickPickupEnabled = mDozeParameters.isQuickPickupEnabled(); final boolean isDocked = mDockManager.isDocked(); mBlankScreen = mDisplayRequiresBlanking; mFrontTint = Color.BLACK; - mFrontAlpha = (alwaysOnEnabled || isDocked) ? mAodFrontScrimAlpha : 1f; + mFrontAlpha = (alwaysOnEnabled || isDocked || quickPickupEnabled) + ? mAodFrontScrimAlpha : 1f; mBehindTint = Color.BLACK; mBehindAlpha = ScrimController.TRANSPARENT; 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 0807f8aa5607..117921dd860c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -95,6 +95,7 @@ import android.provider.Settings; import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; import android.service.notification.StatusBarNotification; +import android.text.TextUtils; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.EventLog; @@ -4071,7 +4072,9 @@ public class StatusBar extends SystemUI implements DemoMode, private @Nullable Intent getEmergencyActionIntent() { Intent emergencyIntent = new Intent(EmergencyGesture.ACTION_LAUNCH_EMERGENCY); PackageManager pm = mContext.getPackageManager(); - ResolveInfo resolveInfo = pm.resolveActivity(emergencyIntent, /*flags=*/0); + List<ResolveInfo> emergencyActivities = pm.queryIntentActivities(emergencyIntent, + PackageManager.MATCH_SYSTEM_ONLY); + ResolveInfo resolveInfo = getTopEmergencySosInfo(emergencyActivities); if (resolveInfo == null) { Log.wtf(TAG, "Couldn't find an app to process the emergency intent."); return null; @@ -4082,6 +4085,34 @@ public class StatusBar extends SystemUI implements DemoMode, return emergencyIntent; } + /** + * Select and return the "best" ResolveInfo for Emergency SOS Activity. + */ + private @Nullable ResolveInfo getTopEmergencySosInfo(List<ResolveInfo> emergencyActivities) { + // No matched activity. + if (emergencyActivities == null || emergencyActivities.isEmpty()) { + return null; + } + + // Of multiple matched Activities, give preference to the pre-set package name. + String preferredAppPackageName = + mContext.getString(R.string.config_preferredEmergencySosPackage); + + // If there is no preferred app, then return first match. + if (TextUtils.isEmpty(preferredAppPackageName)) { + return emergencyActivities.get(0); + } + + for (ResolveInfo emergencyInfo: emergencyActivities) { + // If activity is from the preferred app, use it. + if (TextUtils.equals(emergencyInfo.activityInfo.packageName, preferredAppPackageName)) { + return emergencyInfo; + } + } + // No matching activity: return first match + return emergencyActivities.get(0); + } + boolean isCameraAllowedByAdmin() { if (mDevicePolicyManager.getCameraDisabled(null, mLockscreenUserManager.getCurrentUserId())) { 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 5083e330f9a0..01ada0f4c86c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -76,7 +76,7 @@ import javax.inject.Inject; * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done, * which is in turn, reported to this class by the current - * {@link com.android.keyguard.KeyguardViewBase}. + * {@link com.android.keyguard.KeyguardViewController}. */ @SysUISingleton public class StatusBarKeyguardViewManager implements RemoteInputController.Callback, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 34673f2503ce..801ac964777b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -356,9 +356,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit if (isActivityIntent || canBubble) { mAssistManagerLazy.get().hideAssist(); } - if (shouldCollapse()) { - collapseOnMainThread(); - } NotificationVisibility.NotificationLocation location = NotificationLogger.getNotificationLocation(entry); @@ -408,6 +405,12 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mMainThreadHandler.post( () -> mBubblesManagerOptional.get().expandStackAndSelectBubble(entry)); } + + // expandStackAndSelectBubble won't affect shouldCollapse, so we can collapse directly even + // if we are not on the main thread. + if (shouldCollapse()) { + collapseOnMainThread(); + } } private void startNotificationIntent( @@ -438,6 +441,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit null, null, options); mMainThreadHandler.post(() -> { mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent); + if (shouldCollapse()) { + collapseOnMainThread(); + } }); } catch (RemoteException | PendingIntent.CanceledException e) { // the stack trace isn't very helpful here. @@ -465,11 +471,11 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mActivityLaunchAnimator.setLaunchResult(launchResult, true /* isActivityIntent */); removeHUN(row); + if (shouldCollapse()) { + mCommandQueue.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, + true /* force */); + } }); - if (shouldCollapse()) { - mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels( - CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */)); - } }); return true; }, null, false /* afterKeyguardGone */); diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java index fab1655b1262..fd19528e6d55 100644 --- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java +++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java @@ -19,14 +19,13 @@ package com.android.systemui.toast; import android.animation.Animator; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.Application; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.UserHandle; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; @@ -35,6 +34,8 @@ import android.widget.ToastPresenter; import com.android.internal.R; import com.android.launcher3.icons.IconFactory; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.systemui.plugins.ToastPlugin; /** @@ -170,8 +171,13 @@ public class SystemUIToast implements ToastPlugin.Toast { com.android.systemui.R.layout.text_toast, null); ((TextView) toastView.findViewById(com.android.systemui.R.id.text)).setText(mText); - ((ImageView) toastView.findViewById(com.android.systemui.R.id.icon)) - .setImageDrawable(getBadgedIcon(mContext, mPackageName, mUserId)); + Drawable icon = getBadgedIcon(mContext, mPackageName, mUserId); + if (icon == null) { + toastView.findViewById(com.android.systemui.R.id.icon).setVisibility(View.GONE); + } else { + ((ImageView) toastView.findViewById(com.android.systemui.R.id.icon)) + .setImageDrawable(icon); + } } else { toastView = ToastPresenter.getTextToastView(mContext, mText); } @@ -217,18 +223,20 @@ public class SystemUIToast implements ToastPlugin.Toast { */ public static Drawable getBadgedIcon(@NonNull Context context, String packageName, int userId) { - final PackageManager packageManager = context.getPackageManager(); - try { - final ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser( - packageName, PackageManager.GET_META_DATA, userId); - UserHandle user = UserHandle.getUserHandleForUid(appInfo.uid); - IconFactory iconFactory = IconFactory.obtain(context); - Bitmap iconBmp = iconFactory.createBadgedIconBitmap( - appInfo.loadUnbadgedIcon(packageManager), user, false).icon; - return new BitmapDrawable(context.getResources(), iconBmp); - } catch (PackageManager.NameNotFoundException e) { - Log.e("SystemUIToast", "could not load icon for package=" + packageName + " e=" + e); + final ApplicationsState appState = + ApplicationsState.getInstance((Application) context.getApplicationContext()); + final AppEntry appEntry = appState.getEntry(packageName, userId); + + if (!ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(appEntry)) { return null; } + + final ApplicationInfo appInfo = appEntry.info; + UserHandle user = UserHandle.getUserHandleForUid(appInfo.uid); + IconFactory iconFactory = IconFactory.obtain(context); + Bitmap iconBmp = iconFactory.createBadgedIconBitmap( + appInfo.loadUnbadgedIcon(context.getPackageManager()), user, true).icon; + return new BitmapDrawable(context.getResources(), iconBmp); + } } 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 ba58ed282786..5cd3e5787a49 100644 --- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java @@ -52,6 +52,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; @@ -408,14 +409,15 @@ public class GarbageMonitor implements Dumpable { QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, GarbageMonitor monitor ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); gm = monitor; } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index a12326961b08..1b6c61237e29 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -480,8 +480,8 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static StartingWindowController provideStartingWindowController(Context context, - @ShellSplashscreenThread ShellExecutor executor) { - return new StartingWindowController(context, executor); + @ShellAnimationThread ShellExecutor executor, TransactionPool pool) { + return new StartingWindowController(context, executor, pool); } // diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java index c2ade81a9877..0cf343c2d3c4 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -36,6 +36,8 @@ import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.classifier.FalsingCollector; +import com.android.systemui.classifier.FalsingCollectorFake; import org.junit.Before; import org.junit.Test; @@ -69,6 +71,7 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { private KeyguardMessageAreaController mKeyguardMessageAreaController; @Mock private LatencyTracker mLatencyTracker; + private final FalsingCollector mFalsingCollector = new FalsingCollectorFake(); private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController; @@ -84,7 +87,7 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { .thenReturn(mKeyguardMessageArea); mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, - mKeyguardMessageAreaControllerFactory, mLatencyTracker) { + mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector) { @Override void resetState() { } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index c69ec1a254c3..fc93dedc4e8e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt @@ -24,6 +24,8 @@ import com.android.internal.widget.LockPatternUtils import com.android.internal.widget.LockPatternView import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.classifier.FalsingCollectorFake import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -48,6 +50,7 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback @Mock private lateinit var mLatencyTracker: LatencyTracker + private var mFalsingCollector: FalsingCollector = FalsingCollectorFake() @Mock private lateinit var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory @@ -72,7 +75,7 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { .thenReturn(mKeyguardMessageAreaController) mKeyguardPatternViewController = KeyguardPatternViewController(mKeyguardPatternView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, - mLatencyTracker, mKeyguardMessageAreaControllerFactory) + mLatencyTracker, mFalsingCollector, mKeyguardMessageAreaControllerFactory) } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java index 31cc7bb7c958..33a0dcd048ae 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java @@ -33,6 +33,7 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollectorFake; +import com.android.systemui.classifier.SingleTapClassifier; import org.junit.Before; import org.junit.Test; @@ -69,9 +70,12 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { private LiftToActivateListener mLiftToactivateListener; private FalsingCollector mFalsingCollector = new FalsingCollectorFake(); @Mock + private SingleTapClassifier mSingleTapClassifier; + @Mock private View mDeleteButton; @Mock private View mOkButton; + private NumPadKey[] mButtons = new NumPadKey[]{}; private KeyguardPinBasedInputViewController mKeyguardPinViewController; @@ -83,6 +87,7 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { when(mPinBasedInputView.getPasswordTextViewId()).thenReturn(1); when(mPinBasedInputView.findViewById(1)).thenReturn(mPasswordEntry); when(mPinBasedInputView.isAttachedToWindow()).thenReturn(true); + when(mPinBasedInputView.getButtons()).thenReturn(mButtons); when(mPinBasedInputView.findViewById(R.id.keyguard_message_area)) .thenReturn(mKeyguardMessageArea); when(mPinBasedInputView.findViewById(R.id.delete_button)) diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index b03dc94fde33..49ba646420a3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -34,6 +34,8 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.SysuiTestCase; +import com.android.systemui.classifier.FalsingManagerFake; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -83,6 +85,9 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController; @Mock private ConfigurationController mConfigurationController; + @Mock + private KeyguardViewController mKeyguardViewController; + private FalsingManager mFalsingManager = new FalsingManagerFake(); private KeyguardSecurityContainerController mKeyguardSecurityContainerController; @@ -96,7 +101,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils, mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger, mKeyguardStateController, mKeyguardSecurityViewFlipperController, - mConfigurationController).create(mSecurityCallback); + mConfigurationController, mKeyguardViewController, mFalsingManager) + .create(mSecurityCallback); } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index eb95d1653e84..b9d8d27b8971 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -793,36 +793,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test - public void testStartUdfpsServiceOnShadeLocked() { - // GIVEN - // - bouncer isn't showing - // - user has authenticated since boot - setKeyguardBouncerVisibility(false /* isVisible */); - when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true); - - // WHEN the status bar state changes to SHADE_LOCKED - mStatusBarStateListener.onStateChanged(StatusBarState.SHADE_LOCKED); - - // THEN we shouldn't listen for udfps - assertThat(mKeyguardUpdateMonitor.shouldListenForUdfps()).isEqualTo(false); - } - - @Test - public void testStartUdfpsServiceOnFullscreenUserSwitcher() { - // GIVEN - // - bouncer isn't showing - // - user has authenticated since boot - setKeyguardBouncerVisibility(false /* isVisible */); - when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true); - - // WHEN the status bar state changes to FULLSCREEN_USER_SWITCHER - mStatusBarStateListener.onStateChanged(StatusBarState.FULLSCREEN_USER_SWITCHER); - - // THEN we shouldn't listen for udfps - assertThat(mKeyguardUpdateMonitor.shouldListenForUdfps()).isEqualTo(false); - } - - @Test public void testStartUdfpsServiceNoAuthenticationSinceLastBoot() { // GIVEN // - bouncer isn't showing diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java index 49282ee360e2..7f8be9125316 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java @@ -22,10 +22,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.content.Context; import android.hardware.biometrics.PromptInfo; @@ -333,16 +331,50 @@ public class AuthBiometricViewTest extends SysuiTestCase { } @Test - public void testUdfpsBottomSpacerCalculation() { + public void testUdfpsBottomSpacerHeightForPortrait() { final int displayHeightPx = 3000; final int navbarHeightPx = 10; final int dialogBottomMarginPx = 20; + final int buttonBarHeightPx = 100; + final int textIndicatorHeightPx = 200; - final View buttonBar = mock(View.class); - when(buttonBar.getMeasuredHeight()).thenReturn(100); + final int sensorLocationX = 540; + final int sensorLocationY = 1600; + final int sensorRadius = 100; + final FingerprintSensorPropertiesInternal props = new FingerprintSensorPropertiesInternal( + 0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */, + FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, + true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY, + sensorRadius); + + assertEquals(970, + AuthBiometricUdfpsView.calculateBottomSpacerHeightForPortrait( + props, displayHeightPx, textIndicatorHeightPx, buttonBarHeightPx, + dialogBottomMarginPx, navbarHeightPx + )); + } - final View textIndicator = mock(View.class); - when(textIndicator.getMeasuredHeight()).thenReturn(200); + @Test + public void testUdfpsBottomSpacerHeightForLandscape() { + final int titleHeightPx = 320; + final int subtitleHeightPx = 240; + final int descriptionHeightPx = 200; + final int topSpacerHeightPx = 550; + final int textIndicatorHeightPx = 190; + final int buttonBarHeightPx = 160; + final int navbarBottomInsetPx = 75; + + assertEquals(885, + AuthBiometricUdfpsView.calculateBottomSpacerHeightForLandscape( + titleHeightPx, subtitleHeightPx, descriptionHeightPx, topSpacerHeightPx, + textIndicatorHeightPx, buttonBarHeightPx, navbarBottomInsetPx)); + } + + @Test + public void testUdfpsHorizontalSpacerWidthForLandscape() { + final int displayWidthPx = 3000; + final int dialogMarginPx = 20; + final int navbarHorizontalInsetPx = 75; final int sensorLocationX = 540; final int sensorLocationY = 1600; @@ -353,9 +385,9 @@ public class AuthBiometricViewTest extends SysuiTestCase { true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY, sensorRadius); - assertEquals(970, AuthBiometricUdfpsView.calculateBottomSpacerHeight( - displayHeightPx, navbarHeightPx, dialogBottomMarginPx, buttonBar, textIndicator, - props)); + assertEquals(1205, + AuthBiometricUdfpsView.calculateHorizontalSpacerWidthForLandscape( + props, displayWidthPx, dialogMarginPx, navbarHorizontalInsetPx)); } private PromptInfo buildPromptInfo(boolean allowDeviceCredential) { 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 07686181649d..d6f4958942dd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -246,20 +246,4 @@ public class UdfpsControllerTest extends SysuiTestCase { // THEN the illumination is hidden verify(mUdfpsView).stopIllumination(); } - - @Test - public void registersAndUnregistersViewForCallbacks() throws RemoteException { - mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, - IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); - mFgExecutor.runAllReady(); - verify(mStatusBarStateController).addCallback(mUdfpsController.mStatusBarStateListener); - verify(mStatusBar).addExpansionChangedListener( - mUdfpsController.mStatusBarExpansionListener); - - mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID); - mFgExecutor.runAllReady(); - verify(mStatusBarStateController).removeCallback(mUdfpsController.mStatusBarStateListener); - verify(mStatusBar).removeExpansionChangedListener( - mUdfpsController.mStatusBarExpansionListener); - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java new file mode 100644 index 000000000000..480b33556b27 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.phone.StatusBar; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { + // Dependencies + @Mock + private UdfpsKeyguardView mView; + @Mock + private StatusBarStateController mStatusBarStateController; + @Mock + private StatusBar mStatusBar; + + private UdfpsKeyguardViewController mController; + + // Capture listeners so that they can be used to send events + @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerCaptor; + private StatusBarStateController.StateListener mParentListener; + private StatusBarStateController.StateListener mDozeListener; + + @Captor private ArgumentCaptor<StatusBar.ExpansionChangedListener> mExpansionListenerCaptor; + private StatusBar.ExpansionChangedListener mExpansionListener; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mController = new UdfpsKeyguardViewController( + mView, + mStatusBarStateController, + mStatusBar); + } + + @Test + public void testRegistersExpansionChangedListenerOnAttached() { + mController.onViewAttached(); + captureExpansionListener(); + } + + @Test + public void testRegistersStatusBarStateListenersOnAttached() { + mController.onViewAttached(); + captureStatusBarStateListeners(); + } + + @Test + public void testViewControllerQueriesSBStateOnAttached() { + mController.onViewAttached(); + verify(mStatusBarStateController).getState(); + verify(mStatusBarStateController).getDozeAmount(); + + final float dozeAmount = .88f; + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED); + when(mStatusBarStateController.getDozeAmount()).thenReturn(dozeAmount); + captureStatusBarStateListeners(); + + mController.onViewAttached(); + verify(mView).setPauseAuth(true); + verify(mView).onDozeAmountChanged(dozeAmount, dozeAmount); + } + + @Test + public void testListenersUnregisteredOnDetached() { + mController.onViewAttached(); + captureStatusBarStateListeners(); + captureExpansionListener(); + mController.onViewDetached(); + + verify(mStatusBarStateController).removeCallback(mParentListener); + verify(mStatusBarStateController).removeCallback(mDozeListener); + verify(mStatusBar).removeExpansionChangedListener(mExpansionListener); + } + + @Test + public void testDozeEventsSentToView() { + mController.onViewAttached(); + captureStatusBarStateListeners(); + + final float linear = .55f; + final float eased = .65f; + mDozeListener.onDozeAmountChanged(linear, eased); + + verify(mView).onDozeAmountChanged(linear, eased); + } + + private void captureStatusBarStateListeners() { + verify(mStatusBarStateController, times(2)).addCallback(mStateListenerCaptor.capture()); + List<StatusBarStateController.StateListener> stateListeners = + mStateListenerCaptor.getAllValues(); + mParentListener = stateListeners.get(0); + mDozeListener = stateListeners.get(1); + } + + private void captureExpansionListener() { + verify(mStatusBar).addExpansionChangedListener(mExpansionListenerCaptor.capture()); + mExpansionListener = mExpansionListenerCaptor.getValue(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java index 5709ce3035a2..b2328504272a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java @@ -21,10 +21,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.ArgumentMatchers.anyDouble; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -93,7 +90,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList); mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager, mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier, - mHistoryTracker, mFakeExecutor, DOUBLE_TAP_TIMEOUT_MS, false); + mHistoryTracker, false); ArgumentCaptor<GestureCompleteListener> gestureCompleteListenerCaptor = @@ -161,25 +158,27 @@ public class BrightLineClassifierTest extends SysuiTestCase { public void testIsFalseTap_BasicCheck() { when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mFalsedResult); - assertThat(mBrightLineFalsingManager.isFalseTap(false)).isTrue(); + assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isTrue(); when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult); - assertThat(mBrightLineFalsingManager.isFalseTap(false)).isFalse(); + assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isFalse(); } @Test public void testIsFalseTap_RobustCheck_NoFaceAuth() { when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult); + when(mDoubleTapClassifier.classifyGesture()).thenReturn(mFalsedResult); + when(mHistoryTracker.falseBelief()).thenReturn(1.0); mFalsingDataProvider.setJustUnlockedWithFace(false); - assertThat(mBrightLineFalsingManager.isFalseTap(true)).isTrue(); + assertThat(mBrightLineFalsingManager.isFalseTap(true, 0)).isTrue(); } @Test public void testIsFalseTap_RobustCheck_FaceAuth() { when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult); when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true); - assertThat(mBrightLineFalsingManager.isFalseTap(true)).isFalse(); + assertThat(mBrightLineFalsingManager.isFalseTap(true, 0)).isFalse(); } @Test @@ -203,43 +202,29 @@ public class BrightLineClassifierTest extends SysuiTestCase { @Test public void testHistory_singleTap() { // When trying to classify single taps, we don't immediately add results to history. - mBrightLineFalsingManager.isFalseTap(false); + mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); - - verify(mHistoryTracker, never()).addResults(any(), anyLong()); - - mFakeExecutor.advanceClockToNext(); - mFakeExecutor.runAllReady(); - verify(mHistoryTracker).addResults(anyCollection(), eq(1000L)); } @Test public void testHistory_multipleSingleTaps() { // When trying to classify single taps, we don't immediately add results to history. - mBrightLineFalsingManager.isFalseTap(false); + mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); - mBrightLineFalsingManager.isFalseTap(false); + mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(2000); - - verify(mHistoryTracker, never()).addResults(any(), anyLong()); - - mFakeExecutor.advanceClockToNext(); - mFakeExecutor.runNextReady(); verify(mHistoryTracker).addResults(anyCollection(), eq(1000L)); - reset(mHistoryTracker); - mFakeExecutor.advanceClockToNext(); - mFakeExecutor.runNextReady(); verify(mHistoryTracker).addResults(anyCollection(), eq(2000L)); } @Test public void testHistory_doubleTap() { // When trying to classify single taps, we don't immediately add results to history. - mBrightLineFalsingManager.isFalseTap(false); + mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); // Before checking for double tap, we may check for single-tap on the second gesture. - mBrightLineFalsingManager.isFalseTap(false); + mBrightLineFalsingManager.isFalseTap(false, 0); mBrightLineFalsingManager.isFalseDoubleTap(); mGestureCompleteListener.onGestureComplete(2000); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java index 472ed7a22fe3..ca0a4aa2b04d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java @@ -21,7 +21,6 @@ import static com.android.systemui.classifier.Classifier.UNLOCK; import android.util.DisplayMetrics; import android.view.MotionEvent; -import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.utils.leaks.FakeBatteryController; import com.android.systemui.utils.leaks.LeakCheckedTest; @@ -45,8 +44,7 @@ public class ClassifierTest extends LeakCheckedTest { displayMetrics.widthPixels = 1000; displayMetrics.heightPixels = 1000; mFakeBatteryController = new FakeBatteryController(getLeakCheck()); - mDataProvider = new FalsingDataProvider(displayMetrics, mFakeBatteryController, - new FakeSystemClock()); + mDataProvider = new FalsingDataProvider(displayMetrics, mFakeBatteryController); mDataProvider.setInteractionType(UNLOCK); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java index 17c2700c5bda..4e1742497d90 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java @@ -19,7 +19,6 @@ package com.android.systemui.classifier; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; @@ -35,8 +34,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; -import java.util.Deque; -import java.util.LinkedList; import java.util.List; @SmallTest @@ -47,7 +44,7 @@ public class DoubleTapClassifierTest extends ClassifierTest { private static final long DOUBLE_TAP_TIMEOUT_MS = 100; private List<MotionEvent> mMotionEvents = new ArrayList<>(); - private final Deque<List<MotionEvent>> mHistoricalMotionEvents = new LinkedList<>(); + private List<MotionEvent> mPriorMotionEvents = new ArrayList<>(); @Mock private FalsingDataProvider mDataProvider; @@ -64,7 +61,7 @@ public class DoubleTapClassifierTest extends ClassifierTest { MockitoAnnotations.initMocks(this); mClassifier = new DoubleTapClassifier(mDataProvider, mSingleTapClassifier, TOUCH_SLOP, DOUBLE_TAP_TIMEOUT_MS); - doReturn(mHistoricalMotionEvents).when(mDataProvider).getHistoricalMotionEvents(); + when(mDataProvider.getPriorMotionEvents()).thenReturn(mPriorMotionEvents); } @After @@ -177,9 +174,8 @@ public class DoubleTapClassifierTest extends ClassifierTest { } private void archiveMotionEvents() { - mHistoricalMotionEvents.addFirst(mMotionEvents); - doReturn(mHistoricalMotionEvents).when(mDataProvider).getHistoricalMotionEvents(); + mPriorMotionEvents = mMotionEvents; + when(mDataProvider.getPriorMotionEvents()).thenReturn(mPriorMotionEvents); mMotionEvents = new ArrayList<>(); - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java index 23ef865750b2..dc79b8881891 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java @@ -36,6 +36,7 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.sensors.ThresholdSensor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -56,6 +57,8 @@ public class FalsingCollectorImplTest extends SysuiTestCase { @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock + private HistoryTracker mHistoryTracker; + @Mock private ProximitySensor mProximitySensor; @Mock private SysuiStatusBarStateController mStatusBarStateController; @@ -67,7 +70,8 @@ public class FalsingCollectorImplTest extends SysuiTestCase { when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); mFalsingCollector = new FalsingCollectorImpl(mFalsingDataProvider, mFalsingManager, - mKeyguardUpdateMonitor, mProximitySensor, mStatusBarStateController); + mKeyguardUpdateMonitor, mHistoryTracker, mProximitySensor, + mStatusBarStateController, new FakeSystemClock()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java index be0cc97a2f0f..ebdda67a90d0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java @@ -26,7 +26,6 @@ import android.view.MotionEvent; import androidx.test.filters.SmallTest; -import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.utils.leaks.FakeBatteryController; import org.junit.After; @@ -52,8 +51,7 @@ public class FalsingDataProviderTest extends ClassifierTest { displayMetrics.ydpi = 100; displayMetrics.widthPixels = 1000; displayMetrics.heightPixels = 1000; - mDataProvider = new FalsingDataProvider(displayMetrics, mFakeBatteryController, - new FakeSystemClock()); + mDataProvider = new FalsingDataProvider(displayMetrics, mFakeBatteryController); } @After diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java index 01cce3579b0c..bb7545f93b4b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java @@ -48,14 +48,14 @@ public class HistoryTrackerTest extends SysuiTestCase { @Test public void testNoDataNoPenalty() { - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0); + assertThat(mHistoryTracker.falseBelief()).isEqualTo(0.5); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0); } @Test public void testOneResultFullConfidence() { addResult(true, 1); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); } @@ -64,8 +64,8 @@ public class HistoryTrackerTest extends SysuiTestCase { addResult(true, 1); addResult(false, 1); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0.5); - assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0.5); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(0.5); + assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(0.5); } @Test @@ -73,20 +73,20 @@ public class HistoryTrackerTest extends SysuiTestCase { addResult(true, 1); addResult(true, 0); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0.75); - assertThat(mHistoryTracker.falseConfidence()).isEqualTo(.75); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1); + assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(.75); } @Test public void testDecay() { addResult(true, 1); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); - mSystemClock.advanceTime(1000); + mSystemClock.advanceTime(9999); - assertThat(mHistoryTracker.falsePenalty()).isWithin(0.01).of(0.1); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.005).of(0.55); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); } @@ -96,25 +96,25 @@ public class HistoryTrackerTest extends SysuiTestCase { mSystemClock.advanceTime(1000); addResult(false, .5); - assertThat(mHistoryTracker.falsePenalty()).isWithin(0.01).of(0.17); - assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0.625); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.01).of(0.74); + assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(0.625); } @Test public void testCompleteDecay() { addResult(true, 1); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); - mSystemClock.advanceTime(2999); + mSystemClock.advanceTime(9999); - assertThat(mHistoryTracker.falsePenalty()).isGreaterThan(0); + assertThat(mHistoryTracker.falseBelief()).isGreaterThan(0); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); mSystemClock.advanceTime(1); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0); + assertThat(mHistoryTracker.falseBelief()).isEqualTo(0.5); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java index 6e312594a2e4..901196f8bbba 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java @@ -89,20 +89,4 @@ public class TimeLimitedMotionEventBufferTest extends SysuiTestCase { assertThat(mBuffer.get(0), is(eventC)); assertThat(mBuffer.get(1), is(eventD)); } - - @Test - public void testFullyExpired() { - MotionEvent eventA = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); - MotionEvent eventB = MotionEvent.obtain(0, 1, MotionEvent.ACTION_MOVE, 0, 0, 0); - MotionEvent eventC = MotionEvent.obtain(0, 2, MotionEvent.ACTION_MOVE, 0, 0, 0); - MotionEvent eventD = MotionEvent.obtain(0, 3, MotionEvent.ACTION_UP, 0, 0, 0); - - mBuffer.add(eventA); - mBuffer.add(eventB); - mBuffer.add(eventC); - mBuffer.add(eventD); - - assertThat(mBuffer.isFullyExpired(2), is(false)); - assertThat(mBuffer.isFullyExpired(6), is(true)); - } } 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 9fd9b470a83b..1aeb0d8a5361 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java @@ -60,6 +60,7 @@ public class DozeConfigurationUtil { when(config.tapSensorType()).thenReturn(null); when(config.longPressSensorType()).thenReturn(null); when(config.udfpsLongPressSensorType()).thenReturn(null); + when(config.quickPickupSensorType()).thenReturn(null); when(config.tapGestureEnabled(anyInt())).thenReturn(true); when(config.tapSensorAvailable()).thenReturn(true); @@ -67,6 +68,7 @@ public class DozeConfigurationUtil { when(config.dozePickupSensorAvailable()).thenReturn(false); when(config.wakeScreenGestureAvailable()).thenReturn(false); + when(config.quickPickupSensorEnabled(anyInt())).thenReturn(false); doneHolder[0] = true; return config; 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 27187a85c040..1817fdfd4cdc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -104,7 +104,7 @@ public class DozeTriggersTest extends SysuiTestCase { mTriggers = new DozeTriggers(mContext, mHost, mAlarmManager, config, parameters, asyncSensorManager, wakeLock, mDockManager, mProximitySensor, mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher, new FakeSettings(), - mAuthController); + mAuthController, mExecutor, mExecutor); mTriggers.setDozeMachine(mMachine); waitForSensorManager(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java index 1062fae52e7a..eedf09936b4d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java @@ -46,16 +46,12 @@ import android.service.dreams.IDreamManager; import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.util.FeatureFlagUtils; import android.view.IWindowManager; import android.view.View; import android.view.WindowManagerPolicyConstants; import android.widget.FrameLayout; import androidx.test.filters.SmallTest; -import androidx.test.uiautomator.By; -import androidx.test.uiautomator.UiObject2; -import androidx.test.uiautomator.Until; import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.logging.MetricsLogger; @@ -251,22 +247,6 @@ public class GlobalActionsDialogTest extends SysuiTestCase { } @Test - public void testShouldLogScreenshotLongPress() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SCREENRECORD_LONG_PRESS, true); - GlobalActionsDialog.ScreenshotAction screenshotAction = - mGlobalActionsDialog.makeScreenshotActionForTesting(); - screenshotAction.onLongPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS); - - // Dismiss ScreenRecordDialog opened by the long press above. - final UiObject2 cancelButton = getUiDevice().wait( - Until.findObject(By.text(CANCEL_BUTTON)), UI_TIMEOUT_MILLIS); - if (cancelButton != null) { - cancelButton.click(); - } - } - - @Test public void testShouldShowScreenshot() { mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.integer.config_navBarInteractionMode, 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 2a4b41cbfe32..3fed07472c35 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java @@ -22,8 +22,9 @@ import static android.app.people.ConversationStatus.ACTIVITY_GAME; import static android.app.people.ConversationStatus.ACTIVITY_NEW_STORY; import static android.app.people.ConversationStatus.AVAILABILITY_AVAILABLE; -import static com.android.systemui.people.PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE; import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME; +import static com.android.systemui.people.PeopleSpaceUtils.getPeopleTileFromPersistentStorage; +import static com.android.systemui.people.widget.AppWidgetOptionsHelper.OPTIONS_PEOPLE_TILE; import static com.google.common.truth.Truth.assertThat; @@ -76,6 +77,7 @@ import android.widget.TextView; 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.SbnBuilder; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -232,7 +234,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; Bundle options = new Bundle(); - options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE); + options.putParcelable(OPTIONS_PEOPLE_TILE, PERSON_TILE); when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray); when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT))) @@ -500,7 +502,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { .build(); PeopleSpaceTile actual = PeopleSpaceUtils .augmentTileFromVisibleNotifications(mContext, tile, - Map.of(PeopleSpaceUtils.getKey(mNotificationEntry1), mNotificationEntry1)); + Map.of(new PeopleTileKey(mNotificationEntry1), mNotificationEntry1)); assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_2); } @@ -515,7 +517,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { .build(); PeopleSpaceTile actual = PeopleSpaceUtils .augmentTileFromVisibleNotifications(mContext, tile, - Map.of(PeopleSpaceUtils.getKey(mNotificationEntry1), mNotificationEntry1)); + Map.of(new PeopleTileKey(mNotificationEntry1), mNotificationEntry1)); assertThat(actual.getNotificationContent()).isEqualTo(null); } @@ -818,6 +820,23 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { assertEquals(statusContent.getText(), NOTIFICATION_CONTENT); } + @Test + public void testGetPeopleTileFromPersistentStorageExistingConversation() + throws Exception { + when(mPeopleManager.getConversation(PACKAGE_NAME, 0, SHORTCUT_ID_1)).thenReturn( + getConversationChannelWithoutTimestamp(SHORTCUT_ID_1)); + PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID_1, 0, PACKAGE_NAME); + PeopleSpaceTile tile = getPeopleTileFromPersistentStorage(mContext, key, mPeopleManager); + assertThat(tile.getId()).isEqualTo(key.getShortcutId()); + } + + @Test + public void testGetPeopleTileFromPersistentStorageNoConversation() { + PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID_2, 0, PACKAGE_NAME); + PeopleSpaceTile tile = getPeopleTileFromPersistentStorage(mContext, key, mPeopleManager); + assertThat(tile).isNull(); + } + private ConversationChannelWrapper getConversationChannelWrapper(String shortcutId, boolean importantConversation, long lastInteractionTimestamp) throws Exception { ConversationChannelWrapper convo = new ConversationChannelWrapper(); @@ -843,4 +862,13 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { eq(shortcutId))).thenReturn(lastInteractionTimestamp); return convo; } + + private ConversationChannel getConversationChannelWithoutTimestamp(String shortcutId) + throws Exception { + ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel( + "name").build(); + ConversationChannel convo = new ConversationChannel(shortcutInfo, 0, null, null, + 0L, false); + return convo; + } }
\ No newline at end of file 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 f60fa099feaa..aef75beb3d56 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 @@ -23,10 +23,11 @@ import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY; import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY; import static android.app.people.ConversationStatus.ACTIVITY_GAME; +import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_STRING; import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID; -import static com.android.systemui.people.PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE; import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME; import static com.android.systemui.people.PeopleSpaceUtils.USER_ID; +import static com.android.systemui.people.widget.AppWidgetOptionsHelper.OPTIONS_PEOPLE_TILE; import static com.google.common.truth.Truth.assertThat; @@ -104,13 +105,14 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { private static final int WIDGET_ID_WITH_SHORTCUT = 1; private static final int SECOND_WIDGET_ID_WITH_SHORTCUT = 3; private static final int WIDGET_ID_WITHOUT_SHORTCUT = 2; + private static final int WIDGET_ID_WITH_KEY_IN_OPTIONS = 4; private static final String SHORTCUT_ID = "101"; private static final String OTHER_SHORTCUT_ID = "102"; private static final String NOTIFICATION_KEY = "0|com.android.systemui.tests|0|null|0"; private static final String NOTIFICATION_CONTENT = "message text"; 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 KEY = PeopleSpaceUtils.getKey(SHORTCUT_ID, TEST_PACKAGE_A, 0); + private static final PeopleTileKey KEY = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); private static final Person PERSON = new Person.Builder() .setName("name") .setKey("abc") @@ -172,10 +174,11 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); + clearStorage(); setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_WITH_SHORTCUT); Bundle options = new Bundle(); - options.putParcelable(PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE); + options.putParcelable(OPTIONS_PEOPLE_TILE, PERSON_TILE); when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT))) .thenReturn(options); when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITHOUT_SHORTCUT))) @@ -395,7 +398,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), mBundleArgumentCaptor.capture()); Bundle bundle = mBundleArgumentCaptor.getValue(); - PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_SPACE_TILE); + PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tile.getStatuses()).containsExactly(status); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), any()); @@ -439,7 +442,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), mBundleArgumentCaptor.capture()); Bundle bundle = mBundleArgumentCaptor.getValue(); - PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_SPACE_TILE); + PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); assertThat(tile.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), @@ -473,7 +476,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { throws Exception { addSecondWidgetForPersonTile(); - PeopleSpaceUtils.removeStorageForTile(mContext, KEY, SECOND_WIDGET_ID_WITH_SHORTCUT); + PeopleSpaceUtils.removeSharedPreferencesStorageForTile( + mContext, KEY, SECOND_WIDGET_ID_WITH_SHORTCUT); NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() .setSbn(createNotification( SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false)) @@ -510,7 +514,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { mBundleArgumentCaptor.capture()); Bundle bundle = requireNonNull(mBundleArgumentCaptor.getValue()); - PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_SPACE_TILE); + PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); assertThat(tile.getNotificationContent()) .isEqualTo(mContext.getString(R.string.missed_call)); @@ -536,7 +540,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { mBundleArgumentCaptor.capture()); Bundle bundle = requireNonNull(mBundleArgumentCaptor.getValue()); - PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_SPACE_TILE); + PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); assertThat(tile.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), @@ -547,6 +551,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { public void testUpdateNotificationRemovedIfExistingTile() throws Exception { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); + setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_WITH_SHORTCUT); StatusBarNotification sbn = createNotification( SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false); @@ -560,11 +565,11 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { verify(mAppWidgetManager, times(2)).updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), mBundleArgumentCaptor.capture()); Bundle bundle = mBundleArgumentCaptor.getValue(); - PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_SPACE_TILE); + PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tile.getNotificationKey()).isEqualTo(null); assertThat(tile.getNotificationContent()).isEqualTo(null); assertThat(tile.getNotificationDataUri()).isEqualTo(null); - verify(mAppWidgetManager, times(2)).updateAppWidget(anyInt(), + verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), any()); } @@ -585,7 +590,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { assertThat(widgetSp.getString(SHORTCUT_ID, null)).isNull(); assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); - assertThat(sp.getStringSet(KEY, new HashSet<>())).containsExactly( + assertThat(sp.getStringSet(KEY.toString(), new HashSet<>())).containsExactly( String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT)); // Check listener & shortcut caching remain for other widget. verify(mPeopleManager, never()).unregisterConversationListener(any()); @@ -603,7 +608,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { assertThat(secondWidgetSp.getString(PACKAGE_NAME, null)).isNull(); assertThat(secondWidgetSp.getString(SHORTCUT_ID, null)).isNull(); assertThat(secondWidgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID); - assertThat(sp.getStringSet(KEY, new HashSet<>())).isEmpty(); + assertThat(sp.getStringSet(KEY.toString(), new HashSet<>())).isEmpty(); // Check listener is removed and shortcut is uncached. verify(mPeopleManager, times(1)).unregisterConversationListener(any()); verify(mLauncherApps, times(1)).uncacheShortcuts(eq(TEST_PACKAGE_A), @@ -611,13 +616,96 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS)); } + @Test + public void testUpdateWidgetsWithEmptyOptionsAddsPeopleTileToOptions() throws Exception { + int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT}; + when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); + when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT))) + .thenReturn(new Bundle()); + + mManager.updateWidgets(widgetIdsArray); + mClock.advanceTime(MIN_LINGER_DURATION); + + // If we had to fetch Tile from persistent storage, we want to make sure we write it to + // options. + verify(mAppWidgetManager, times(1)) + .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), + mBundleArgumentCaptor.capture()); + Bundle bundle = mBundleArgumentCaptor.getValue(); + PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE); + assertThat(tile.getId()).isEqualTo(SHORTCUT_ID); + verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), + any()); + } + + @Test + public void testOnAppWidgetOptionsChangedNoWidgetAdded() { + Bundle newOptions = new Bundle(); + newOptions.putParcelable(OPTIONS_PEOPLE_TILE, PERSON_TILE); + mManager.onAppWidgetOptionsChanged(SECOND_WIDGET_ID_WITH_SHORTCUT, newOptions); + + + // Check that options is not modified + verify(mAppWidgetManager, never()).updateAppWidgetOptions( + eq(SECOND_WIDGET_ID_WITH_SHORTCUT), any()); + // Check listener is not added and shortcut is not cached. + verify(mPeopleManager, never()).registerConversationListener(any(), anyInt(), any(), any(), + any()); + verify(mLauncherApps, never()).cacheShortcuts(any(), any(), any(), anyInt()); + // Check no added storage. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); + assertThat(sp.getStringSet(KEY.toString(), new HashSet<>())) + .doesNotContain(SECOND_WIDGET_ID_WITH_SHORTCUT); + SharedPreferences widgetSp = mContext.getSharedPreferences( + String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT), + Context.MODE_PRIVATE); + assertThat(widgetSp.getString(PACKAGE_NAME, EMPTY_STRING)).isEqualTo(EMPTY_STRING); + assertThat(widgetSp.getString(SHORTCUT_ID, EMPTY_STRING)).isEqualTo(EMPTY_STRING); + assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID); + + } + + @Test + public void testOnAppWidgetOptionsChangedWidgetAdded() { + Bundle newOptions = new Bundle(); + newOptions.putString(PeopleSpaceUtils.SHORTCUT_ID, SHORTCUT_ID); + newOptions.putInt(USER_ID, 0); + newOptions.putString(PACKAGE_NAME, TEST_PACKAGE_A); + when(mAppWidgetManager.getAppWidgetOptions(eq(SECOND_WIDGET_ID_WITH_SHORTCUT))) + .thenReturn(newOptions); + + mManager.onAppWidgetOptionsChanged(SECOND_WIDGET_ID_WITH_SHORTCUT, newOptions); + + verify(mAppWidgetManager, times(1)).updateAppWidgetOptions( + eq(SECOND_WIDGET_ID_WITH_SHORTCUT), mBundleArgumentCaptor.capture()); + Bundle bundle = mBundleArgumentCaptor.getValue(); + assertThat(bundle.getString(PeopleSpaceUtils.SHORTCUT_ID, EMPTY_STRING)) + .isEqualTo(EMPTY_STRING); + assertThat(bundle.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID); + assertThat(bundle.getString(PACKAGE_NAME, EMPTY_STRING)).isEqualTo(EMPTY_STRING); + verify(mLauncherApps, times(1)).cacheShortcuts(eq(TEST_PACKAGE_A), + eq(Arrays.asList(SHORTCUT_ID)), eq(UserHandle.of(0)), + eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS)); + + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); + assertThat(sp.getStringSet(KEY.toString(), new HashSet<>())).contains( + String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT)); + SharedPreferences widgetSp = mContext.getSharedPreferences( + String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT), + Context.MODE_PRIVATE); + assertThat(widgetSp.getString(PACKAGE_NAME, EMPTY_STRING)).isEqualTo(TEST_PACKAGE_A); + assertThat(widgetSp.getString(PeopleSpaceUtils.SHORTCUT_ID, EMPTY_STRING)) + .isEqualTo(SHORTCUT_ID); + assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(0); + } + /** * Adds another widget for {@code PERSON_TILE} with widget ID: {@code * SECOND_WIDGET_ID_WITH_SHORTCUT}. */ private void addSecondWidgetForPersonTile() { Bundle options = new Bundle(); - options.putParcelable(PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE); + options.putParcelable(OPTIONS_PEOPLE_TILE, PERSON_TILE); when(mAppWidgetManager.getAppWidgetOptions(eq(SECOND_WIDGET_ID_WITH_SHORTCUT))) .thenReturn(options); // Set the same Person associated on another People Tile widget ID. @@ -676,6 +764,27 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { .build(); } + private void clearStorage() { + SharedPreferences widgetSp1 = mContext.getSharedPreferences( + String.valueOf(WIDGET_ID_WITH_SHORTCUT), + Context.MODE_PRIVATE); + widgetSp1.edit().clear().commit(); + SharedPreferences widgetSp2 = mContext.getSharedPreferences( + String.valueOf(WIDGET_ID_WITHOUT_SHORTCUT), + Context.MODE_PRIVATE); + widgetSp2.edit().clear().commit(); + SharedPreferences widgetSp3 = mContext.getSharedPreferences( + String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT), + Context.MODE_PRIVATE); + widgetSp3.edit().clear().commit(); + SharedPreferences widgetSp4 = mContext.getSharedPreferences( + String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS), + Context.MODE_PRIVATE); + widgetSp4.edit().clear().commit(); + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); + sp.edit().clear().commit(); + } + private void setStorageForTile(String shortcutId, String packageName, int widgetId) { SharedPreferences widgetSp = mContext.getSharedPreferences( String.valueOf(widgetId), @@ -689,7 +798,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); SharedPreferences.Editor editor = sp.edit(); editor.putString(String.valueOf(widgetId), shortcutId); - String key = PeopleSpaceUtils.getKey(shortcutId, packageName, 0); + String key = new PeopleTileKey(shortcutId, 0, packageName).toString(); Set<String> storedWidgetIds = new HashSet<>(sp.getStringSet(key, new HashSet<>())); storedWidgetIds.add(String.valueOf(widgetId)); editor.putStringSet(key, storedWidgetIds); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index cfef5beb94e0..2ca8082f777a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -49,6 +49,7 @@ import com.android.internal.util.CollectionUtils; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSFactory; @@ -360,6 +361,7 @@ public class QSTileHostTest extends SysuiTestCase { host, mLooper.getLooper(), new Handler(mLooper.getLooper()), + new FalsingManagerFake(), mock(MetricsLogger.class), mock(StatusBarStateController.class), mock(ActivityStarter.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt index 3aa40dec1fad..b1c3d1da8fea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt @@ -32,6 +32,7 @@ import android.testing.TestableLooper import android.view.IWindowManager import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -103,6 +104,7 @@ class CustomTileTest : SysuiTestCase() { { tileHost }, testableLooper.looper, Handler(testableLooper.looper), + FalsingManagerFake(), metricsLogger, statusBarStateController, activityStarter, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java index 61a0d6c17eed..937ab1c5c41d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java @@ -26,6 +26,8 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_BAR_STATE; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -55,7 +57,9 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.SysuiTestCase; +import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSEvent; @@ -90,6 +94,7 @@ public class QSTileImplTest extends SysuiTestCase { private QSTileHost mHost; @Mock private MetricsLogger mMetricsLogger; + private final FalsingManagerFake mFalsingManager = new FalsingManagerFake(); @Mock private StatusBarStateController mStatusBarStateController; @Mock @@ -112,7 +117,7 @@ public class QSTileImplTest extends SysuiTestCase { Handler mainHandler = new Handler(mTestableLooper.getLooper()); - mTile = new TileImpl(mHost, mTestableLooper.getLooper(), mainHandler, + mTile = new TileImpl(mHost, mTestableLooper.getLooper(), mainHandler, mFalsingManager, mMetricsLogger, mStatusBarStateController, mActivityStarter, mQsLogger); mTile.setTileSpec(SPEC); } @@ -144,6 +149,19 @@ public class QSTileImplTest extends SysuiTestCase { } @Test + public void testClick_falsing() { + mFalsingManager.setFalseRobustTap(true); + mTile.click(); + mTestableLooper.processAllMessages(); + assertThat(mTile.mClicked).isFalse(); + + mFalsingManager.setFalseRobustTap(false); + mTile.click(); + mTestableLooper.processAllMessages(); + assertThat(mTile.mClicked).isTrue(); + } + + @Test public void testSecondaryClick_Metrics() { mTile.secondaryClick(); verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_SECONDARY_CLICK))); @@ -360,17 +378,20 @@ public class QSTileImplTest extends SysuiTestCase { } private static class TileImpl extends QSTileImpl<QSTile.BooleanState> { + boolean mClicked; + protected TileImpl( QSHost host, Looper backgroundLooper, Handler mainHandler, + FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger ) { - super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, - activityStarter, qsLogger); + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); getState().state = Tile.STATE_ACTIVE; } @@ -381,7 +402,7 @@ public class QSTileImplTest extends SysuiTestCase { @Override protected void handleClick() { - + mClicked = true; } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt new file mode 100644 index 000000000000..9674a60c1ac5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt @@ -0,0 +1,149 @@ +package com.android.systemui.qs.tiles + +import android.app.AlarmManager +import android.app.PendingIntent +import android.os.Handler +import android.service.quicksettings.Tile +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.internal.logging.MetricsLogger +import com.android.internal.logging.UiEventLogger +import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingManagerFake +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.qs.QSHost +import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.settings.UserTracker +import com.android.systemui.statusbar.FeatureFlags +import com.android.systemui.statusbar.policy.NextAlarmController +import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.eq +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +class AlarmTileTest : SysuiTestCase() { + + @Mock + private lateinit var qsHost: QSHost + @Mock + private lateinit var metricsLogger: MetricsLogger + @Mock + private lateinit var statusBarStateController: StatusBarStateController + @Mock + private lateinit var activityStarter: ActivityStarter + @Mock + private lateinit var qsLogger: QSLogger + @Mock + private lateinit var featureFlags: FeatureFlags + @Mock + private lateinit var userTracker: UserTracker + @Mock + private lateinit var nextAlarmController: NextAlarmController + @Mock + private lateinit var uiEventLogger: UiEventLogger + @Mock + private lateinit var pendingIntent: PendingIntent + @Captor + private lateinit var callbackCaptor: ArgumentCaptor<NextAlarmController.NextAlarmChangeCallback> + + private lateinit var testableLooper: TestableLooper + private lateinit var tile: AlarmTile + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + testableLooper = TestableLooper.get(this) + + `when`(qsHost.context).thenReturn(mContext) + `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) + + tile = AlarmTile( + qsHost, + testableLooper.looper, + Handler(testableLooper.looper), + FalsingManagerFake(), + metricsLogger, + statusBarStateController, + activityStarter, + qsLogger, + featureFlags, + userTracker, + nextAlarmController + ) + + verify(nextAlarmController).observe(eq(tile), capture(callbackCaptor)) + tile.refreshState() + testableLooper.processAllMessages() + } + + @Test + fun testNotAvailableFeatureFlag() { + `when`(featureFlags.isAlarmTileAvailable).thenReturn(false) + assertThat(tile.isAvailable).isFalse() + } + + @Test + fun testAvailableFeatureFlag() { + `when`(featureFlags.isAlarmTileAvailable).thenReturn(true) + assertThat(tile.isAvailable).isTrue() + } + + @Test + fun testDoesntHandleLongClick() { + assertThat(tile.state.handlesLongClick).isFalse() + } + + @Test + fun testInactiveByDefault() { + assertThat(tile.state.state).isEqualTo(Tile.STATE_INACTIVE) + } + + @Test + fun testInactiveAfterNullNextAlarm() { + callbackCaptor.value.onNextAlarmChanged(null) + + testableLooper.processAllMessages() + assertThat(tile.state.state).isEqualTo(Tile.STATE_INACTIVE) + } + + @Test + fun testActivityStartedWhenNullNextAlarm() { + callbackCaptor.value.onNextAlarmChanged(null) + tile.click() + + testableLooper.processAllMessages() + verify(activityStarter).postStartActivityDismissingKeyguard(tile.defaultIntent, 0) + } + + @Test + fun testActiveAfterNextAlarm() { + val alarmInfo = AlarmManager.AlarmClockInfo(1L, pendingIntent) + callbackCaptor.value.onNextAlarmChanged(alarmInfo) + + testableLooper.processAllMessages() + assertThat(tile.state.state).isEqualTo(Tile.STATE_ACTIVE) + } + + @Test + fun testActivityStartedWhenNextAlarm() { + val alarmInfo = AlarmManager.AlarmClockInfo(1L, pendingIntent) + callbackCaptor.value.onNextAlarmChanged(alarmInfo) + tile.click() + + testableLooper.processAllMessages() + verify(activityStarter).postStartActivityDismissingKeyguard(pendingIntent) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt index bcfc83570345..f17bd56d0052 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt @@ -24,6 +24,7 @@ import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost @@ -79,6 +80,7 @@ class BatterySaverTileTest : SysuiTestCase() { qsHost, testableLooper.looper, Handler(testableLooper.looper), + FalsingManagerFake(), metricsLogger, statusBarStateController, activityStarter, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java index 1c29a8174359..7d393610c2b5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java @@ -37,6 +37,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.systemui.SysuiTestCase; +import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSTileHost; @@ -101,6 +102,7 @@ public class CastTileTest extends SysuiTestCase { mHost, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), + new FalsingManagerFake(), mMetricsLogger, mStatusBarStateController, mActivityStarter, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt index ccd9548b269f..9fe568718908 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt @@ -17,6 +17,8 @@ package com.android.systemui.qs.tiles import android.os.Handler +import android.content.Context +import android.content.Intent import android.provider.Settings import android.service.quicksettings.Tile import android.testing.AndroidTestingRunner @@ -26,11 +28,11 @@ import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.dagger.ControlsComponent import com.android.systemui.controls.management.ControlsListingController -import com.android.systemui.controls.ui.ControlsDialog import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -50,7 +52,9 @@ import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.`when` +import org.mockito.Mockito.doNothing import org.mockito.Mockito.never +import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import java.util.Optional @@ -80,8 +84,6 @@ class DeviceControlsTileTest : SysuiTestCase() { private lateinit var controlsController: ControlsController @Mock private lateinit var featureFlags: FeatureFlags - @Mock - private lateinit var controlsDialog: ControlsDialog private lateinit var globalSettings: GlobalSettings @Mock private lateinit var serviceInfo: ControlsServiceInfo @@ -95,6 +97,7 @@ class DeviceControlsTileTest : SysuiTestCase() { private lateinit var tile: DeviceControlsTile private lateinit var secureSettings: SecureSettings + private lateinit var spiedContext: Context private var featureEnabled = true @Before @@ -103,7 +106,9 @@ class DeviceControlsTileTest : SysuiTestCase() { testableLooper = TestableLooper.get(this) secureSettings = FakeSettings() - `when`(qsHost.context).thenReturn(mContext) + spiedContext = spy(mContext) + doNothing().`when`(spiedContext).startActivity(any(Intent::class.java)) + `when`(qsHost.context).thenReturn(spiedContext) `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) `when`(controlsController.available).thenReturn(true) `when`(controlsComponent.isEnabled()).thenReturn(true) @@ -276,7 +281,7 @@ class DeviceControlsTileTest : SysuiTestCase() { tile.click() testableLooper.processAllMessages() - verify(controlsDialog, never()).show(any(ControlsUiController::class.java)) + verify(spiedContext, never()).startActivity(any(Intent::class.java)) } @Test @@ -293,7 +298,7 @@ class DeviceControlsTileTest : SysuiTestCase() { tile.click() testableLooper.processAllMessages() - verify(controlsDialog).show(controlsUiController) + verify(spiedContext).startActivity(any(Intent::class.java)) } @Test @@ -311,25 +316,7 @@ class DeviceControlsTileTest : SysuiTestCase() { tile.click() testableLooper.processAllMessages() - verify(controlsDialog, never()).show(any(ControlsUiController::class.java)) - } - - @Test - fun testDialogDismissedOnDestroy() { - verify(controlsListingController).observe( - any(LifecycleOwner::class.java), - capture(listingCallbackCaptor) - ) - - listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo)) - testableLooper.processAllMessages() - - tile.click() - testableLooper.processAllMessages() - - tile.destroy() - testableLooper.processAllMessages() - verify(controlsDialog).dismiss() + verify(spiedContext, never()).startActivity(any(Intent::class.java)) } private fun createTile(): DeviceControlsTile { @@ -337,13 +324,13 @@ class DeviceControlsTileTest : SysuiTestCase() { qsHost, testableLooper.looper, Handler(testableLooper.looper), + FalsingManagerFake(), metricsLogger, statusBarStateController, activityStarter, qsLogger, controlsComponent, featureFlags, - { controlsDialog }, globalSettings ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java index b37ac4a2b759..99d028cd8c5c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java @@ -33,6 +33,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSTileHost; @@ -84,6 +85,7 @@ public class NfcTileTest extends SysuiTestCase { mHost, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), + new FalsingManagerFake(), mMetricsLogger, mStatusBarStateController, mActivityStarter, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java index 880c290802df..6032e51ab554 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java @@ -33,6 +33,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSTileHost; @@ -82,6 +83,7 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase { mHost, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), + new FalsingManagerFake(), mMetricsLogger, mStatusBarStateController, mActivityStarter, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java index 6b54791dd143..22154332c953 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java @@ -33,6 +33,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSTileHost; @@ -81,6 +82,7 @@ public class ScreenRecordTileTest extends SysuiTestCase { mHost, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), + new FalsingManagerFake(), mMetricsLogger, mStatusBarStateController, mActivityStarter, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 2917dfafd6a6..8ec03d76cfea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -476,4 +476,11 @@ public class CommandQueueTest extends SysuiTestCase { waitForIdleSync(); verify(mCallbacks).requestWindowMagnificationConnection(true); } + + @Test + public void testSetEnableNavigationBarLumaSampling() { + mCommandQueue.setNavigationBarLumaSamplingEnabled(1, true); + waitForIdleSync(); + verify(mCallbacks).setNavigationBarLumaSamplingEnabled(eq(1), eq(true)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java index 14877eec9a83..30708a7cb2fe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java @@ -127,25 +127,7 @@ public class HighPriorityProviderTest extends SysuiTestCase { .getPeopleNotificationType(entry)) .thenReturn(TYPE_NON_PERSON); - // THEN it has high priority - assertTrue(mHighPriorityProvider.isHighPriority(entry)); - } - - @Test - public void minImportanceForeground() { - // GIVEN notification is low importance and is associated with a foreground service - final Notification notification = mock(Notification.class); - when(notification.isForegroundService()).thenReturn(true); - - final NotificationEntry entry = new NotificationEntryBuilder() - .setNotification(notification) - .setImportance(IMPORTANCE_MIN) - .build(); - when(mPeopleNotificationIdentifier - .getPeopleNotificationType(entry)) - .thenReturn(TYPE_NON_PERSON); - - // THEN it does NOT have high priority + // THEN it has low priority assertFalse(mHighPriorityProvider.isHighPriority(entry)); } @@ -155,7 +137,6 @@ public class HighPriorityProviderTest extends SysuiTestCase { // to less than IMPORTANCE_DEFAULT (ie: IMPORTANCE_LOW or IMPORTANCE_MIN) final Notification notification = new Notification.Builder(mContext, "test") .setStyle(new Notification.MessagingStyle("")) - .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true) .build(); final NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java index 8cd71031a8f8..c1d2ea88a1b1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java @@ -322,23 +322,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { } @Test - public void testPeopleFiltering_addHeadersFromShowingOnlyGentle() { - enablePeopleFiltering(); - - setStackState( - GENTLE_HEADER, - PERSON, - ALERTING, - GENTLE); - mSectionsManager.updateSectionBoundaries(); - - verify(mNssl).changeViewPosition(mSectionsManager.getSilentHeaderView(), 2); - verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1); - verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0); - } - - @Test - public void testPeopleFiltering_addAllHeaders() { + public void testPeopleFiltering_onlyAddSilentHeader() { enablePeopleFiltering(); setStackState( @@ -348,26 +332,6 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mSectionsManager.updateSectionBoundaries(); verify(mNssl).addView(mSectionsManager.getSilentHeaderView(), 2); - verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1); - verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0); - } - - @Test - public void testPeopleFiltering_moveAllHeaders() { - enablePeopleFiltering(); - - setStackState( - PEOPLE_HEADER, - ALERTING_HEADER, - GENTLE_HEADER, - PERSON, - ALERTING, - GENTLE); - mSectionsManager.updateSectionBoundaries(); - - verify(mNssl).changeViewPosition(mSectionsManager.getSilentHeaderView(), 4); - verify(mNssl).changeViewPosition(mSectionsManager.getAlertingHeaderView(), 2); - verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0); } @Test @@ -385,9 +349,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mSectionsManager.updateSectionBoundaries(); verifyMockStack( - ChildType.INCOMING_HEADER, ChildType.HEADS_UP, - ChildType.PEOPLE_HEADER, ChildType.PERSON, ChildType.GENTLE_HEADER, ChildType.GENTLE @@ -408,10 +370,8 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mSectionsManager.updateSectionBoundaries(); verifyMockStack( - ChildType.INCOMING_HEADER, ChildType.HEADS_UP, ChildType.HEADS_UP, - ChildType.PEOPLE_HEADER, ChildType.PERSON ); } @@ -428,7 +388,6 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mSectionsManager.updateSectionBoundaries(); verifyMockStack( - ChildType.PEOPLE_HEADER, ChildType.PERSON, ChildType.PERSON ); @@ -444,9 +403,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { ); mSectionsManager.updateSectionBoundaries(); verifyMockStack( - ChildType.INCOMING_HEADER, ChildType.HEADS_UP, - ChildType.PEOPLE_HEADER, ChildType.PERSON ); } @@ -467,12 +424,9 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mSectionsManager.updateSectionBoundaries(); verifyMockStack( - ChildType.INCOMING_HEADER, ChildType.HEADS_UP, ChildType.FSN, - ChildType.PEOPLE_HEADER, ChildType.PERSON, - ChildType.ALERTING_HEADER, ChildType.ALERTING, ChildType.GENTLE_HEADER, ChildType.GENTLE @@ -517,7 +471,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { } @Test - public void testRemoveIncomingHeader() { + public void testRemoveNonSilentHeader() { enablePeopleFiltering(); enableMediaControls(); @@ -539,9 +493,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { verifyMockStack( ChildType.MEDIA_CONTROLS, - ChildType.PEOPLE_HEADER, ChildType.PERSON, - ChildType.ALERTING_HEADER, ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, @@ -569,13 +521,10 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mSectionsManager.updateSectionBoundaries(); verifyMockStack( - ChildType.INCOMING_HEADER, ChildType.HEADS_UP, ChildType.HEADS_UP, ChildType.HEADS_UP, - ChildType.PEOPLE_HEADER, ChildType.PERSON, - ChildType.ALERTING_HEADER, ChildType.ALERTING ); } @@ -593,7 +542,6 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mSectionsManager.updateSectionBoundaries(); verifyMockStack( - ChildType.ALERTING_HEADER, ChildType.PERSON, ChildType.ALERTING, ChildType.GENTLE_HEADER, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java index bdde82289e86..8b5ba3848500 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java @@ -174,6 +174,7 @@ public class DozeServiceHostTest extends SysuiTestCase { DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, DozeLog.PULSE_REASON_DOCKING, DozeLog.REASON_SENSOR_WAKE_UP, + DozeLog.REASON_SENSOR_QUICK_PICKUP, DozeLog.REASON_SENSOR_TAP)); HashSet<Integer> reasonsThatDontPulse = new HashSet<>( Arrays.asList(DozeLog.REASON_SENSOR_PICKUP, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java index a844d099d43a..a60baa54541e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java @@ -45,6 +45,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; @@ -86,6 +87,7 @@ public class RemoteInputViewTest extends SysuiTestCase { mRemoteInputQuickSettingsDisabler); mDependency.injectTestDependency(LightBarController.class, mLightBarController); + mDependency.injectMockDependency(NotificationRemoteInputManager.class); mReceiver = new BlockingQueueIntentReceiver(); mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION), null, diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java index 238bf0f5a335..d420bd4bdb66 100644 --- a/rs/java/android/renderscript/Allocation.java +++ b/rs/java/android/renderscript/Allocation.java @@ -52,8 +52,12 @@ import android.view.Surface; * <p>For more information about creating an application that uses RenderScript, read the * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p> * </div> + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ - +@Deprecated public class Allocation extends BaseObj { private static final int MAX_NUMBER_IO_INPUT_ALLOC = 16; diff --git a/rs/java/android/renderscript/AllocationAdapter.java b/rs/java/android/renderscript/AllocationAdapter.java index 6d7e97ebb0fe..17bc23421894 100644 --- a/rs/java/android/renderscript/AllocationAdapter.java +++ b/rs/java/android/renderscript/AllocationAdapter.java @@ -19,7 +19,11 @@ package android.renderscript; /** * Only intended for use by generated reflected code. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class AllocationAdapter extends Allocation { Type mWindow; diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java index 7b5514b8a0d1..ea8535d6d621 100644 --- a/rs/java/android/renderscript/BaseObj.java +++ b/rs/java/android/renderscript/BaseObj.java @@ -27,7 +27,11 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * It is responsible for lifetime management and resource tracking. This class * should not be used by a user application. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class BaseObj { BaseObj(long id, RenderScript rs) { rs.validate(); diff --git a/rs/java/android/renderscript/Byte2.java b/rs/java/android/renderscript/Byte2.java index 3ad79e400c91..cb5cc473a48e 100644 --- a/rs/java/android/renderscript/Byte2.java +++ b/rs/java/android/renderscript/Byte2.java @@ -20,7 +20,11 @@ package android.renderscript; /** * Class for exposing the native RenderScript byte2 type back to the Android system. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class Byte2 { public byte x; public byte y; diff --git a/rs/java/android/renderscript/Byte3.java b/rs/java/android/renderscript/Byte3.java index a138313321d0..aca4e645f102 100644 --- a/rs/java/android/renderscript/Byte3.java +++ b/rs/java/android/renderscript/Byte3.java @@ -20,7 +20,11 @@ package android.renderscript; /** * Class for exposing the native RenderScript byte3 type back to the Android system. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class Byte3 { public byte x; public byte y; diff --git a/rs/java/android/renderscript/Byte4.java b/rs/java/android/renderscript/Byte4.java index fa4c13d79714..b30b6ed00d09 100644 --- a/rs/java/android/renderscript/Byte4.java +++ b/rs/java/android/renderscript/Byte4.java @@ -20,7 +20,11 @@ package android.renderscript; /** * Class for exposing the native RenderScript byte4 type back to the Android system. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class Byte4 { public byte x; public byte y; diff --git a/rs/java/android/renderscript/Double2.java b/rs/java/android/renderscript/Double2.java index 4c7319d5a4b0..e14228a6f785 100644 --- a/rs/java/android/renderscript/Double2.java +++ b/rs/java/android/renderscript/Double2.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic double type. * Provides two double fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Double2 { public double x; public double y; diff --git a/rs/java/android/renderscript/Double3.java b/rs/java/android/renderscript/Double3.java index b819716017e9..e52c902a27fa 100644 --- a/rs/java/android/renderscript/Double3.java +++ b/rs/java/android/renderscript/Double3.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic double type. * Provides three double fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Double3 { public double x; public double y; diff --git a/rs/java/android/renderscript/Double4.java b/rs/java/android/renderscript/Double4.java index e4829f7426ae..a3e4a94af8f2 100644 --- a/rs/java/android/renderscript/Double4.java +++ b/rs/java/android/renderscript/Double4.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic double type. * Provides four double fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Double4 { public double x; public double y; diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java index 0941907d35f8..f671953f4704 100644 --- a/rs/java/android/renderscript/Element.java +++ b/rs/java/android/renderscript/Element.java @@ -51,7 +51,12 @@ import android.compat.annotation.UnsupportedAppUsage; * <p>For more information about creating an application that uses RenderScript, read the * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p> * </div> + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class Element extends BaseObj { int mSize; Element[] mElements; diff --git a/rs/java/android/renderscript/FieldPacker.java b/rs/java/android/renderscript/FieldPacker.java index de1c49730aaa..aaa0fe8d7e95 100644 --- a/rs/java/android/renderscript/FieldPacker.java +++ b/rs/java/android/renderscript/FieldPacker.java @@ -26,7 +26,11 @@ import java.util.BitSet; * reflected code generated by the RS tool chain. It should not * be called directly. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class FieldPacker { public FieldPacker(int len) { mPos = 0; diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java index 7cc2825ae565..f0a9fa718a6f 100644 --- a/rs/java/android/renderscript/FileA3D.java +++ b/rs/java/android/renderscript/FileA3D.java @@ -36,6 +36,7 @@ import java.io.InputStream; * index entries for all the objects stored inside it. * **/ +@Deprecated public class FileA3D extends BaseObj { /** diff --git a/rs/java/android/renderscript/Float2.java b/rs/java/android/renderscript/Float2.java index e9f8ca7737ce..1f6038c9bfca 100644 --- a/rs/java/android/renderscript/Float2.java +++ b/rs/java/android/renderscript/Float2.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic float type. * Provides two float fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Float2 { public float x; public float y; diff --git a/rs/java/android/renderscript/Float3.java b/rs/java/android/renderscript/Float3.java index 555bdf6d6e4e..5f4571643daf 100644 --- a/rs/java/android/renderscript/Float3.java +++ b/rs/java/android/renderscript/Float3.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic float type. * Provides three float fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Float3 { public float x; public float y; diff --git a/rs/java/android/renderscript/Float4.java b/rs/java/android/renderscript/Float4.java index 6541b2ec7264..7f3ba2c5fc33 100644 --- a/rs/java/android/renderscript/Float4.java +++ b/rs/java/android/renderscript/Float4.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic float type. * Provides four float fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Float4 { public float x; public float y; diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java index e47ec4b31700..6f6f341d78a6 100644 --- a/rs/java/android/renderscript/Font.java +++ b/rs/java/android/renderscript/Font.java @@ -45,6 +45,7 @@ import java.util.Map; * them in the script to suit the user's rendering needs. Font colors work as a state machine. * Every new call to draw text uses the last color set in the script.</p> **/ +@Deprecated public class Font extends BaseObj { //These help us create a font by family name diff --git a/rs/java/android/renderscript/Int2.java b/rs/java/android/renderscript/Int2.java index 120957bcd726..be0639f7137d 100644 --- a/rs/java/android/renderscript/Int2.java +++ b/rs/java/android/renderscript/Int2.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic int type. * Provides two int fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Int2 { public int x; public int y; diff --git a/rs/java/android/renderscript/Int3.java b/rs/java/android/renderscript/Int3.java index 5431b9a75ba7..38a602d6bb4e 100644 --- a/rs/java/android/renderscript/Int3.java +++ b/rs/java/android/renderscript/Int3.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic int type. * Provides three int fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Int3 { public int x; public int y; diff --git a/rs/java/android/renderscript/Int4.java b/rs/java/android/renderscript/Int4.java index 1c0e2e2621aa..52f7bb2c2461 100644 --- a/rs/java/android/renderscript/Int4.java +++ b/rs/java/android/renderscript/Int4.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic int type. * Provides four int fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Int4 { public int x; public int y; diff --git a/rs/java/android/renderscript/Long2.java b/rs/java/android/renderscript/Long2.java index fabf2046a48c..1b3955b04798 100644 --- a/rs/java/android/renderscript/Long2.java +++ b/rs/java/android/renderscript/Long2.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic long type. * Provides two long fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Long2 { public long x; public long y; diff --git a/rs/java/android/renderscript/Long3.java b/rs/java/android/renderscript/Long3.java index 8e243cce647f..8be9c1cf2774 100644 --- a/rs/java/android/renderscript/Long3.java +++ b/rs/java/android/renderscript/Long3.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic long type. * Provides three long fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Long3 { public long x; public long y; diff --git a/rs/java/android/renderscript/Long4.java b/rs/java/android/renderscript/Long4.java index 1a1ad748e462..75db51b1237a 100644 --- a/rs/java/android/renderscript/Long4.java +++ b/rs/java/android/renderscript/Long4.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic long type. * Provides four long fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Long4 { public long x; public long y; diff --git a/rs/java/android/renderscript/Matrix2f.java b/rs/java/android/renderscript/Matrix2f.java index 048262dc7eba..5f5e709d2c99 100644 --- a/rs/java/android/renderscript/Matrix2f.java +++ b/rs/java/android/renderscript/Matrix2f.java @@ -20,7 +20,11 @@ package android.renderscript; /** * Class for exposing the native RenderScript rs_matrix2x2 type back to the Android system. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class Matrix2f { /** diff --git a/rs/java/android/renderscript/Matrix3f.java b/rs/java/android/renderscript/Matrix3f.java index 9a4af777583c..b620eaf1415d 100644 --- a/rs/java/android/renderscript/Matrix3f.java +++ b/rs/java/android/renderscript/Matrix3f.java @@ -20,7 +20,11 @@ package android.renderscript; /** * Class for exposing the native RenderScript rs_matrix3x3 type back to the Android system. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class Matrix3f { /** diff --git a/rs/java/android/renderscript/Matrix4f.java b/rs/java/android/renderscript/Matrix4f.java index a9469c979494..cdf06a63c59f 100644 --- a/rs/java/android/renderscript/Matrix4f.java +++ b/rs/java/android/renderscript/Matrix4f.java @@ -22,7 +22,11 @@ import android.compat.annotation.UnsupportedAppUsage; /** * Class for exposing the native RenderScript rs_matrix4x4 type back to the Android system. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class Matrix4f { /** diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java index 1a4d1fd5afbb..f2fd5a92afe8 100644 --- a/rs/java/android/renderscript/Mesh.java +++ b/rs/java/android/renderscript/Mesh.java @@ -40,6 +40,7 @@ import java.util.Vector; * index sets or primitive types. * </p> **/ +@Deprecated public class Mesh extends BaseObj { /** diff --git a/rs/java/android/renderscript/Program.java b/rs/java/android/renderscript/Program.java index ff072183e927..3cadc935e67c 100644 --- a/rs/java/android/renderscript/Program.java +++ b/rs/java/android/renderscript/Program.java @@ -32,7 +32,11 @@ import java.io.UnsupportedEncodingException; * Program is a base class for all the objects that modify * various stages of the graphics pipeline * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class Program extends BaseObj { static final int MAX_INPUT = 8; static final int MAX_OUTPUT = 8; diff --git a/rs/java/android/renderscript/ProgramFragment.java b/rs/java/android/renderscript/ProgramFragment.java index 880531207b4d..e2879d8a0d54 100644 --- a/rs/java/android/renderscript/ProgramFragment.java +++ b/rs/java/android/renderscript/ProgramFragment.java @@ -37,6 +37,7 @@ import android.compat.annotation.UnsupportedAppUsage; * </p> * **/ +@Deprecated public class ProgramFragment extends Program { ProgramFragment(long id, RenderScript rs) { super(id, rs); diff --git a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java index c741ce6e77ed..8dbf6f44f137 100644 --- a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java +++ b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java @@ -29,6 +29,7 @@ import android.compat.annotation.UnsupportedAppUsage; * blended with results of up to two texture lookups.</p * **/ +@Deprecated public class ProgramFragmentFixedFunction extends ProgramFragment { ProgramFragmentFixedFunction(long id, RenderScript rs) { super(id, rs); diff --git a/rs/java/android/renderscript/ProgramRaster.java b/rs/java/android/renderscript/ProgramRaster.java index a21696c82161..8b53828918a8 100644 --- a/rs/java/android/renderscript/ProgramRaster.java +++ b/rs/java/android/renderscript/ProgramRaster.java @@ -25,6 +25,7 @@ import android.compat.annotation.UnsupportedAppUsage; * Program raster is primarily used to specify whether point sprites are enabled and to control * the culling mode. By default, back faces are culled. **/ +@Deprecated public class ProgramRaster extends BaseObj { /** diff --git a/rs/java/android/renderscript/ProgramStore.java b/rs/java/android/renderscript/ProgramStore.java index 1952b8860033..c94d2534dad6 100644 --- a/rs/java/android/renderscript/ProgramStore.java +++ b/rs/java/android/renderscript/ProgramStore.java @@ -34,7 +34,11 @@ import android.os.Build; * framebuffer</li> * </ul> * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class ProgramStore extends BaseObj { /** * Specifies the function used to determine whether a fragment diff --git a/rs/java/android/renderscript/ProgramVertex.java b/rs/java/android/renderscript/ProgramVertex.java index 9257234de42c..ecd8a31ed130 100644 --- a/rs/java/android/renderscript/ProgramVertex.java +++ b/rs/java/android/renderscript/ProgramVertex.java @@ -34,7 +34,6 @@ * The signatures don't have to be exact or in any strict order. As long as the input name in the shader * matches a channel name and size available on the mesh, the runtime takes care of connecting the * two. Unlike OpenGL, there is no need to link the vertex and fragment programs.</p> - * **/ package android.renderscript; @@ -49,6 +48,7 @@ import android.compat.annotation.UnsupportedAppUsage; * geometric data in a user-defined way. * **/ +@Deprecated public class ProgramVertex extends Program { ProgramVertex(long id, RenderScript rs) { diff --git a/rs/java/android/renderscript/ProgramVertexFixedFunction.java b/rs/java/android/renderscript/ProgramVertexFixedFunction.java index 03c2eaf91242..4cf2f4c8174f 100644 --- a/rs/java/android/renderscript/ProgramVertexFixedFunction.java +++ b/rs/java/android/renderscript/ProgramVertexFixedFunction.java @@ -27,6 +27,7 @@ import android.compat.annotation.UnsupportedAppUsage; * without writing any GLSL code. * **/ +@Deprecated public class ProgramVertexFixedFunction extends ProgramVertex { ProgramVertexFixedFunction(long id, RenderScript rs) { diff --git a/rs/java/android/renderscript/RSDriverException.java b/rs/java/android/renderscript/RSDriverException.java index 9e6507f517ed..3d0f0bfadbd0 100644 --- a/rs/java/android/renderscript/RSDriverException.java +++ b/rs/java/android/renderscript/RSDriverException.java @@ -20,7 +20,12 @@ package android.renderscript; /** * Base class for all exceptions thrown by the Android * RenderScript + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class RSDriverException extends RSRuntimeException { public RSDriverException(String string) { super(string); diff --git a/rs/java/android/renderscript/RSIllegalArgumentException.java b/rs/java/android/renderscript/RSIllegalArgumentException.java index 5c68594f33a2..d0ac5b681f2f 100644 --- a/rs/java/android/renderscript/RSIllegalArgumentException.java +++ b/rs/java/android/renderscript/RSIllegalArgumentException.java @@ -20,7 +20,12 @@ package android.renderscript; /** * Base class for all exceptions thrown by the Android * RenderScript + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class RSIllegalArgumentException extends RSRuntimeException { public RSIllegalArgumentException(String string) { super(string); diff --git a/rs/java/android/renderscript/RSInvalidStateException.java b/rs/java/android/renderscript/RSInvalidStateException.java index c881898dab3d..5eea41997f35 100644 --- a/rs/java/android/renderscript/RSInvalidStateException.java +++ b/rs/java/android/renderscript/RSInvalidStateException.java @@ -20,7 +20,12 @@ package android.renderscript; /** * Base class for all exceptions thrown by the Android * RenderScript + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class RSInvalidStateException extends RSRuntimeException { public RSInvalidStateException(String string) { super(string); diff --git a/rs/java/android/renderscript/RSRuntimeException.java b/rs/java/android/renderscript/RSRuntimeException.java index b4b629e14184..d52a1c10add0 100644 --- a/rs/java/android/renderscript/RSRuntimeException.java +++ b/rs/java/android/renderscript/RSRuntimeException.java @@ -20,7 +20,12 @@ package android.renderscript; /** * Base class for all exceptions thrown by the Android * RenderScript + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class RSRuntimeException extends java.lang.RuntimeException { public RSRuntimeException(String string) { diff --git a/rs/java/android/renderscript/RSSurfaceView.java b/rs/java/android/renderscript/RSSurfaceView.java index 6bdde387b334..05c0112f1bb7 100644 --- a/rs/java/android/renderscript/RSSurfaceView.java +++ b/rs/java/android/renderscript/RSSurfaceView.java @@ -33,6 +33,7 @@ import android.view.SurfaceView; * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p> * </div> */ +@Deprecated public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mSurfaceHolder; private RenderScriptGL mRS; diff --git a/rs/java/android/renderscript/RSTextureView.java b/rs/java/android/renderscript/RSTextureView.java index af3258a7090d..ed68fc39ddce 100644 --- a/rs/java/android/renderscript/RSTextureView.java +++ b/rs/java/android/renderscript/RSTextureView.java @@ -28,6 +28,7 @@ import android.view.TextureView; * to draw on. * */ +@Deprecated public class RSTextureView extends TextureView implements TextureView.SurfaceTextureListener { private RenderScriptGL mRS; private SurfaceTexture mSurfaceTexture; diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java index 806a25a748e2..855cfdcbdf7b 100644 --- a/rs/java/android/renderscript/RenderScript.java +++ b/rs/java/android/renderscript/RenderScript.java @@ -44,7 +44,12 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * <p>For more information about creating an application that uses RenderScript, read the * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p> * </div> + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class RenderScript { static final long TRACE_TAG = Trace.TRACE_TAG_RS; diff --git a/rs/java/android/renderscript/RenderScriptCacheDir.java b/rs/java/android/renderscript/RenderScriptCacheDir.java index 862d032d6987..cd6e8b14a793 100644 --- a/rs/java/android/renderscript/RenderScriptCacheDir.java +++ b/rs/java/android/renderscript/RenderScriptCacheDir.java @@ -23,7 +23,11 @@ import java.io.File; /** * Used only for tracking the RenderScript cache directory. * @hide + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class RenderScriptCacheDir { /** * Sets the directory to use as a persistent storage for the diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java index dafaf367364d..d46dbf68291b 100644 --- a/rs/java/android/renderscript/RenderScriptGL.java +++ b/rs/java/android/renderscript/RenderScriptGL.java @@ -37,6 +37,7 @@ import android.view.SurfaceHolder; * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p> * </div> **/ +@Deprecated public class RenderScriptGL extends RenderScript { int mWidth; int mHeight; diff --git a/rs/java/android/renderscript/Sampler.java b/rs/java/android/renderscript/Sampler.java index 70e88bc51f79..06f036db3aa5 100644 --- a/rs/java/android/renderscript/Sampler.java +++ b/rs/java/android/renderscript/Sampler.java @@ -25,7 +25,12 @@ package android.renderscript; * android.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE}; using a Sampler on * an {@link android.renderscript.Allocation} that was not created with {@link * android.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE} is undefined. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class Sampler extends BaseObj { public enum Value { NEAREST (0), diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java index d1d3a7642382..f32a2f7ef482 100644 --- a/rs/java/android/renderscript/Script.java +++ b/rs/java/android/renderscript/Script.java @@ -22,7 +22,12 @@ import android.util.SparseArray; /** * The parent class for all executable scripts. This should not be used by * applications. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class Script extends BaseObj { /** diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java index 00ebe5756589..1866a9983495 100644 --- a/rs/java/android/renderscript/ScriptC.java +++ b/rs/java/android/renderscript/ScriptC.java @@ -25,7 +25,12 @@ import java.io.InputStream; /** * The superclass for all user-defined scripts. This is only * intended to be used by the generated derived classes. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class ScriptC extends Script { private static final String TAG = "ScriptC"; diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java index e0bdbfcdfed5..5cdb9cf3b8be 100644 --- a/rs/java/android/renderscript/ScriptGroup.java +++ b/rs/java/android/renderscript/ScriptGroup.java @@ -37,7 +37,12 @@ import java.util.Map; * Grouping kernels together allows for more efficient execution. For example, * runtime and compiler optimization can be applied to reduce computation and * communication overhead, and to make better use of the CPU and the GPU. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public final class ScriptGroup extends BaseObj { private static final String TAG = "ScriptGroup"; IO mOutputs[]; diff --git a/rs/java/android/renderscript/ScriptIntrinsic.java b/rs/java/android/renderscript/ScriptIntrinsic.java index 61211a25f8af..8d654221b4a8 100644 --- a/rs/java/android/renderscript/ScriptIntrinsic.java +++ b/rs/java/android/renderscript/ScriptIntrinsic.java @@ -23,7 +23,12 @@ package android.renderscript; * operations. * * Not intended for direct use. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public abstract class ScriptIntrinsic extends Script { ScriptIntrinsic(long id, RenderScript rs) { super(id, rs); diff --git a/rs/java/android/renderscript/ScriptIntrinsic3DLUT.java b/rs/java/android/renderscript/ScriptIntrinsic3DLUT.java index ce149d9a103a..7a2847e3bfcc 100644 --- a/rs/java/android/renderscript/ScriptIntrinsic3DLUT.java +++ b/rs/java/android/renderscript/ScriptIntrinsic3DLUT.java @@ -23,7 +23,11 @@ package android.renderscript; * allocation. The 8 nearest values are sampled and linearly interpolated. The * result is placed in the output. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public final class ScriptIntrinsic3DLUT extends ScriptIntrinsic { private Allocation mLUT; private Element mElement; diff --git a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java index 49a71b430ac6..16cc79930b76 100644 --- a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java +++ b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java @@ -29,7 +29,11 @@ import java.lang.annotation.RetentionPolicy; * * For detailed description of BLAS, please refer to http://www.netlib.org/blas/ * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public final class ScriptIntrinsicBLAS extends ScriptIntrinsic { private Allocation mLUT; diff --git a/rs/java/android/renderscript/ScriptIntrinsicBlend.java b/rs/java/android/renderscript/ScriptIntrinsicBlend.java index fdcd61b04eca..a1c79ef938c4 100644 --- a/rs/java/android/renderscript/ScriptIntrinsicBlend.java +++ b/rs/java/android/renderscript/ScriptIntrinsicBlend.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Intrinsic kernels for blending two {@link android.renderscript.Allocation} objects. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class ScriptIntrinsicBlend extends ScriptIntrinsic { ScriptIntrinsicBlend(long id, RenderScript rs) { super(id, rs); diff --git a/rs/java/android/renderscript/ScriptIntrinsicBlur.java b/rs/java/android/renderscript/ScriptIntrinsicBlur.java index 0891d5142022..68cbc3f3eaad 100644 --- a/rs/java/android/renderscript/ScriptIntrinsicBlur.java +++ b/rs/java/android/renderscript/ScriptIntrinsicBlur.java @@ -20,8 +20,11 @@ package android.renderscript; * Intrinsic Gausian blur filter. Applies a gaussian blur of the * specified radius to all elements of an allocation. * - * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public final class ScriptIntrinsicBlur extends ScriptIntrinsic { private final float[] mValues = new float[9]; private Allocation mInput; diff --git a/rs/java/android/renderscript/ScriptIntrinsicColorMatrix.java b/rs/java/android/renderscript/ScriptIntrinsicColorMatrix.java index e8a299c28c51..4a05cf54e13f 100644 --- a/rs/java/android/renderscript/ScriptIntrinsicColorMatrix.java +++ b/rs/java/android/renderscript/ScriptIntrinsicColorMatrix.java @@ -36,7 +36,12 @@ package android.renderscript; * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4}, * {@link Element#F32}, {@link Element#F32_2}, {@link * Element#F32_3}, and {@link Element#F32_4}. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public final class ScriptIntrinsicColorMatrix extends ScriptIntrinsic { private final Matrix4f mMatrix = new Matrix4f(); private final Float4 mAdd = new Float4(); diff --git a/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java b/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java index 9fe7b2d8f0ef..4b9dff18f62e 100644 --- a/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java +++ b/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java @@ -19,7 +19,11 @@ package android.renderscript; /** * Intrinsic for applying a 3x3 convolve to an allocation. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public final class ScriptIntrinsicConvolve3x3 extends ScriptIntrinsic { private final float[] mValues = new float[9]; private Allocation mInput; diff --git a/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java b/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java index 8518bb27379d..ed93c7eda0a8 100644 --- a/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java +++ b/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java @@ -19,7 +19,11 @@ package android.renderscript; /** * Intrinsic for applying a 5x5 convolve to an allocation. * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public final class ScriptIntrinsicConvolve5x5 extends ScriptIntrinsic { private final float[] mValues = new float[25]; private Allocation mInput; diff --git a/rs/java/android/renderscript/ScriptIntrinsicHistogram.java b/rs/java/android/renderscript/ScriptIntrinsicHistogram.java index 0e8b36c11952..4a71bc8c41ca 100644 --- a/rs/java/android/renderscript/ScriptIntrinsicHistogram.java +++ b/rs/java/android/renderscript/ScriptIntrinsicHistogram.java @@ -19,8 +19,11 @@ package android.renderscript; /** * Intrinsic Histogram filter. * - * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public final class ScriptIntrinsicHistogram extends ScriptIntrinsic { private Allocation mOut; diff --git a/rs/java/android/renderscript/ScriptIntrinsicLUT.java b/rs/java/android/renderscript/ScriptIntrinsicLUT.java index e90462d11124..7d5b09fb41aa 100644 --- a/rs/java/android/renderscript/ScriptIntrinsicLUT.java +++ b/rs/java/android/renderscript/ScriptIntrinsicLUT.java @@ -21,7 +21,12 @@ package android.renderscript; * channel of the input has an independant lookup table. The * tables are 256 entries in size and can cover the full value * range of {@link Element#U8_4}. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public final class ScriptIntrinsicLUT extends ScriptIntrinsic { private final Matrix4f mMatrix = new Matrix4f(); private Allocation mTables; diff --git a/rs/java/android/renderscript/ScriptIntrinsicResize.java b/rs/java/android/renderscript/ScriptIntrinsicResize.java index 45b0a646b924..a87fe95e2225 100644 --- a/rs/java/android/renderscript/ScriptIntrinsicResize.java +++ b/rs/java/android/renderscript/ScriptIntrinsicResize.java @@ -18,7 +18,12 @@ package android.renderscript; /** * Intrinsic for performing a resize of a 2D allocation. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public final class ScriptIntrinsicResize extends ScriptIntrinsic { private Allocation mInput; diff --git a/rs/java/android/renderscript/ScriptIntrinsicYuvToRGB.java b/rs/java/android/renderscript/ScriptIntrinsicYuvToRGB.java index e64c91103c8f..a94f9167d953 100644 --- a/rs/java/android/renderscript/ScriptIntrinsicYuvToRGB.java +++ b/rs/java/android/renderscript/ScriptIntrinsicYuvToRGB.java @@ -23,7 +23,12 @@ package android.renderscript; * The input allocation should be supplied in a supported YUV format * as a YUV element Allocation. The output is RGBA; the alpha channel * will be set to 255. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public final class ScriptIntrinsicYuvToRGB extends ScriptIntrinsic { private Allocation mInput; diff --git a/rs/java/android/renderscript/Short2.java b/rs/java/android/renderscript/Short2.java index 24809f739159..4565eb4c11d4 100644 --- a/rs/java/android/renderscript/Short2.java +++ b/rs/java/android/renderscript/Short2.java @@ -22,7 +22,12 @@ package android.renderscript; * * Vector version of the basic short type. * Provides two short fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Short2 { public short x; public short y; diff --git a/rs/java/android/renderscript/Short3.java b/rs/java/android/renderscript/Short3.java index 661db0a89f3d..3d70f078e483 100644 --- a/rs/java/android/renderscript/Short3.java +++ b/rs/java/android/renderscript/Short3.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic short type. * Provides three short fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Short3 { public short x; public short y; diff --git a/rs/java/android/renderscript/Short4.java b/rs/java/android/renderscript/Short4.java index a2d74f2ccf94..c90d64876e32 100644 --- a/rs/java/android/renderscript/Short4.java +++ b/rs/java/android/renderscript/Short4.java @@ -19,7 +19,12 @@ package android.renderscript; /** * Vector version of the basic short type. * Provides four short fields packed. + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. */ +@Deprecated public class Short4 { public short x; public short y; diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java index dc2378596d00..021fd06b3535 100644 --- a/rs/java/android/renderscript/Type.java +++ b/rs/java/android/renderscript/Type.java @@ -42,7 +42,12 @@ package android.renderscript; * <p>For more information about creating an application that uses RenderScript, read the * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p> * </div> + * + * @deprecated Renderscript has been deprecated in API level 31. Please refer to the <a + * href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration + * guide</a> for the proposed alternatives. **/ +@Deprecated public class Type extends BaseObj { int mDimX; int mDimY; diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk index e41073bcdb76..0caba421dca8 100644 --- a/rs/jni/Android.mk +++ b/rs/jni/Android.mk @@ -25,7 +25,7 @@ LOCAL_C_INCLUDES += \ frameworks/rs LOCAL_CFLAGS += -Wno-unused-parameter -LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code +LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -Wno-deprecated-declarations LOCAL_MODULE:= librs_jni LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0 diff --git a/services/api/Android.bp b/services/api/Android.bp index e69de29bb2d1..b8ca5488c5cd 100644 --- a/services/api/Android.bp +++ b/services/api/Android.bp @@ -0,0 +1,29 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_visibility: ["//visibility:private"], +} + +filegroup { + name: "non-updatable-system-server-current.txt", + srcs: ["non-updatable-current.txt"], + visibility: ["//frameworks/base/api"], +} + +filegroup { + name: "non-updatable-system-server-removed.txt", + srcs: ["non-updatable-removed.txt"], + visibility: ["//frameworks/base/api"], +}
\ No newline at end of file diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 52237c934797..4b5684511757 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -766,6 +766,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind .get(association.getPackageName()); if (serviceConnector != null) { serviceConnector.unbind(); + restartBleScan(); } } } @@ -1067,11 +1068,19 @@ public class CompanionDeviceManagerService extends SystemService implements Bind } void onDeviceDisconnected(String address) { - Slog.d(LOG_TAG, "onDeviceConnected(address = " + address + ")"); + Slog.d(LOG_TAG, "onDeviceDisconnected(address = " + address + ")"); mCurrentlyConnectedDevices.remove(address); - onDeviceDisappeared(address); + Date lastSeen = mDevicesLastNearby.get(address); + if (isDeviceDisappeared(lastSeen)) { + onDeviceDisappeared(address); + } + } + + private boolean isDeviceDisappeared(Date lastSeen) { + return lastSeen == null || System.currentTimeMillis() - lastSeen.getTime() + >= DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS; } private ServiceConnector<ICompanionDeviceService> getDeviceListenerServiceConnector( @@ -1172,8 +1181,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind String address = mDevicesLastNearby.keyAt(i); Date lastNearby = mDevicesLastNearby.valueAt(i); - if (System.currentTimeMillis() - lastNearby.getTime() - >= DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS) { + if (isDeviceDisappeared(lastNearby)) { for (Association association : getAllAssociations(address)) { if (association.isNotifyOnDeviceNearby()) { getDeviceListenerServiceConnector(association).unbind(); diff --git a/services/core/Android.bp b/services/core/Android.bp index 8ccfad6fe061..b00689be3656 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -98,7 +98,6 @@ java_library_static { ":platform-compat-overrides", ":display-device-config", ":display-layout-config", - ":cec-config", ":device-state-config", "java/com/android/server/EventLogTags.logtags", "java/com/android/server/am/EventLogTags.logtags", @@ -119,7 +118,6 @@ java_library_static { ], required: [ - "cec_config.xml", "gps_debug.conf", "protolog.conf.json.gz", ], @@ -185,11 +183,6 @@ java_library_host { } prebuilt_etc { - name: "cec_config.xml", - src: "java/com/android/server/hdmi/cec_config.xml", -} - -prebuilt_etc { name: "gps_debug.conf", src: "java/com/android/server/location/gnss/gps_debug.conf", } @@ -223,6 +216,7 @@ filegroup { "java/com/android/server/TestNetworkService.java", "java/com/android/server/connectivity/AutodestructReference.java", "java/com/android/server/connectivity/ConnectivityConstants.java", + "java/com/android/server/connectivity/ConnectivityResources.java", "java/com/android/server/connectivity/DnsManager.java", "java/com/android/server/connectivity/KeepaliveTracker.java", "java/com/android/server/connectivity/LingerMonitor.java", diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index bb4bbd5bc6d4..fbfde436a16f 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -918,19 +918,7 @@ public final class BatteryService extends SystemService { int opts = parseOptions(shell); getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); - if (!mUpdatesStopped) { - copy(mLastHealthInfo, mHealthInfo); - } - mHealthInfo.chargerAcOnline = false; - mHealthInfo.chargerUsbOnline = false; - mHealthInfo.chargerWirelessOnline = false; - final long ident = Binder.clearCallingIdentity(); - try { - mUpdatesStopped = true; - processValuesFromShellLocked(pw, opts); - } finally { - Binder.restoreCallingIdentity(ident); - } + unplugBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw); } break; case "set": { int opts = parseOptions(shell); @@ -990,7 +978,8 @@ public final class BatteryService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { mUpdatesStopped = true; - processValuesFromShellLocked(pw, opts); + processValuesLocked( + /* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw); } finally { Binder.restoreCallingIdentity(ident); } @@ -1004,30 +993,12 @@ public final class BatteryService extends SystemService { int opts = parseOptions(shell); getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); - final long ident = Binder.clearCallingIdentity(); - try { - if (mUpdatesStopped) { - mUpdatesStopped = false; - copy(mHealthInfo, mLastHealthInfo); - processValuesFromShellLocked(pw, opts); - } - } finally { - Binder.restoreCallingIdentity(ident); - } - if (mBatteryInputSuspended) { - PowerProperties.battery_input_suspended(false); - mBatteryInputSuspended = false; - } + resetBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw); } break; case "suspend_input": { - if (!Build.IS_DEBUGGABLE) { - throw new SecurityException( - "battery suspend_input is only supported on debuggable builds"); - } getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); - PowerProperties.battery_input_suspended(true); - mBatteryInputSuspended = true; + suspendBatteryInput(); } break; default: return shell.handleDefaultCommands(cmd); @@ -1035,9 +1006,59 @@ public final class BatteryService extends SystemService { return 0; } - private void processValuesFromShellLocked(PrintWriter pw, int opts) { - processValuesLocked((opts & OPTION_FORCE_UPDATE) != 0); - if ((opts & OPTION_FORCE_UPDATE) != 0) { + private void setChargerAcOnline(boolean online, boolean forceUpdate) { + if (!mUpdatesStopped) { + copy(mLastHealthInfo, mHealthInfo); + } + mHealthInfo.chargerAcOnline = online; + mUpdatesStopped = true; + Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate)); + } + + private void setBatteryLevel(int level, boolean forceUpdate) { + if (!mUpdatesStopped) { + copy(mLastHealthInfo, mHealthInfo); + } + mHealthInfo.batteryLevel = level; + mUpdatesStopped = true; + Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate)); + } + + private void unplugBattery(boolean forceUpdate, PrintWriter pw) { + if (!mUpdatesStopped) { + copy(mLastHealthInfo, mHealthInfo); + } + mHealthInfo.chargerAcOnline = false; + mHealthInfo.chargerUsbOnline = false; + mHealthInfo.chargerWirelessOnline = false; + mUpdatesStopped = true; + Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw)); + } + + private void resetBattery(boolean forceUpdate, @Nullable PrintWriter pw) { + if (mUpdatesStopped) { + mUpdatesStopped = false; + copy(mHealthInfo, mLastHealthInfo); + Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw)); + } + if (mBatteryInputSuspended) { + PowerProperties.battery_input_suspended(false); + mBatteryInputSuspended = false; + } + } + + private void suspendBatteryInput() { + if (!Build.IS_DEBUGGABLE) { + throw new SecurityException( + "battery suspend_input is only supported on debuggable builds"); + } + PowerProperties.battery_input_suspended(true); + mBatteryInputSuspended = true; + } + + private void processValuesLocked(boolean forceUpdate, @Nullable PrintWriter pw) { + processValuesLocked(forceUpdate); + if (pw != null && forceUpdate) { pw.println(mSequence); } } @@ -1363,6 +1384,41 @@ public final class BatteryService extends SystemService { return mInvalidCharger; } } + + @Override + public void setChargerAcOnline(boolean online, boolean forceUpdate) { + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, /* message= */ null); + BatteryService.this.setChargerAcOnline(online, forceUpdate); + } + + @Override + public void setBatteryLevel(int level, boolean forceUpdate) { + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, /* message= */ null); + BatteryService.this.setBatteryLevel(level, forceUpdate); + } + + @Override + public void unplugBattery(boolean forceUpdate) { + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, /* message= */ null); + BatteryService.this.unplugBattery(forceUpdate, /* printWriter= */ null); + } + + @Override + public void resetBattery(boolean forceUpdate) { + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, /* message= */ null); + BatteryService.this.resetBattery(forceUpdate, /* printWriter= */ null); + } + + @Override + public void suspendBatteryInput() { + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, /* message= */ null); + BatteryService.this.suspendBatteryInput(); + } } /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 07b473caa9cc..b4fcaeedd845 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -85,6 +85,7 @@ import android.net.ConnectionInfo; import android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import android.net.ConnectivityDiagnosticsManager.DataStallReport; import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; import android.net.DataStallReportParcelable; import android.net.DnsResolverServiceManager; import android.net.ICaptivePortal; @@ -175,6 +176,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.sysprop.NetworkProperties; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArrayMap; @@ -186,11 +188,8 @@ import android.util.SparseArray; import android.util.SparseIntArray; import com.android.connectivity.aidl.INetworkAgent; -import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.app.IBatteryStats; -import com.android.internal.util.AsyncChannel; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.LocationPermissionChecker; import com.android.internal.util.MessageUtils; @@ -201,8 +200,8 @@ import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; import com.android.net.module.util.LinkPropertiesUtils.CompareResult; import com.android.net.module.util.NetworkCapabilitiesUtils; import com.android.net.module.util.PermissionUtils; -import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.AutodestructReference; +import com.android.server.connectivity.ConnectivityResources; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate; import com.android.server.connectivity.KeepaliveTracker; @@ -217,7 +216,6 @@ import com.android.server.connectivity.PermissionMonitor; import com.android.server.connectivity.ProxyTracker; import com.android.server.connectivity.QosCallbackTracker; import com.android.server.net.NetworkPolicyManagerInternal; -import com.android.server.utils.PriorityDump; import libcore.io.IoUtils; @@ -319,6 +317,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private boolean mRestrictBackground; private final Context mContext; + private final ConnectivityResources mResources; // The Context is created for UserHandle.ALL. private final Context mUserAllContext; private final Dependencies mDeps; @@ -346,8 +345,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private String mCurrentTcpBufferSizes; private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames( - new Class[] { AsyncChannel.class, ConnectivityService.class, NetworkAgent.class, - NetworkAgentInfo.class }); + new Class[] { ConnectivityService.class, NetworkAgent.class, NetworkAgentInfo.class }); private enum ReapUnvalidatedNetworks { // Tear down networks that have no chance (e.g. even if validated) of becoming @@ -607,7 +605,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private Intent mInitialBroadcast; private PowerManager.WakeLock mNetTransitionWakeLock; - private int mNetTransitionWakeLockTimeout; private final PowerManager.WakeLock mPendingIntentWakeLock; // A helper object to track the current default HTTP proxy. ConnectivityService needs to tell @@ -884,27 +881,59 @@ public class ConnectivityService extends IConnectivityManager.Stub } private final LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker(this); + final LocalPriorityDump mPriorityDumper = new LocalPriorityDump(); /** * Helper class which parses out priority arguments and dumps sections according to their * priority. If priority arguments are omitted, function calls the legacy dump command. */ - private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() { - @Override - public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) { - doDump(fd, pw, new String[] {DIAG_ARG}, asProto); - doDump(fd, pw, new String[] {SHORT_ARG}, asProto); + private class LocalPriorityDump { + private static final String PRIORITY_ARG = "--dump-priority"; + private static final String PRIORITY_ARG_HIGH = "HIGH"; + private static final String PRIORITY_ARG_NORMAL = "NORMAL"; + + LocalPriorityDump() {} + + private void dumpHigh(FileDescriptor fd, PrintWriter pw) { + doDump(fd, pw, new String[] {DIAG_ARG}); + doDump(fd, pw, new String[] {SHORT_ARG}); } - @Override - public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) { - doDump(fd, pw, args, asProto); + private void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) { + doDump(fd, pw, args); } - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) { - doDump(fd, pw, args, asProto); + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (args == null) { + dumpNormal(fd, pw, args); + return; + } + + String priority = null; + for (int argIndex = 0; argIndex < args.length; argIndex++) { + if (args[argIndex].equals(PRIORITY_ARG) && argIndex + 1 < args.length) { + argIndex++; + priority = args[argIndex]; + } + } + + if (PRIORITY_ARG_HIGH.equals(priority)) { + dumpHigh(fd, pw); + } else if (PRIORITY_ARG_NORMAL.equals(priority)) { + dumpNormal(fd, pw, args); + } else { + // ConnectivityService publishes binder service using publishBinderService() with + // no priority assigned will be treated as NORMAL priority. Dumpsys does not send + // "--dump-priority" arguments to the service. Thus, dump both NORMAL and HIGH to + // align the legacy design. + // TODO: Integrate into signal dump. + dumpNormal(fd, pw, args); + pw.println(); + pw.println("DUMP OF SERVICE HIGH connectivity"); + pw.println(); + dumpHigh(fd, pw); + } } - }; + } /** * Keeps track of the number of requests made under different uids. @@ -983,6 +1012,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** + * Get the {@link ConnectivityResources} to use in ConnectivityService. + */ + public ConnectivityResources getResources(@NonNull Context ctx) { + return new ConnectivityResources(ctx); + } + + /** * Create a HandlerThread to use in ConnectivityService. */ public HandlerThread makeHandlerThread() { @@ -1035,19 +1071,19 @@ public class ConnectivityService extends IConnectivityManager.Stub return new MultinetworkPolicyTracker(c, h, r); } - public IBatteryStats getBatteryStatsService() { - return BatteryStatsService.getService(); - } - /** * @see BatteryStatsManager */ public void reportNetworkInterfaceForTransports(Context context, String iface, int[] transportTypes) { - final BatteryStatsManager batteryStats = + final BatteryStatsManager batteryStats = context.getSystemService(BatteryStatsManager.class); batteryStats.reportNetworkInterfaceForTransports(iface, transportTypes); } + + public boolean getCellular464XlatEnabled() { + return NetworkProperties.isCellular464XlatEnabled().orElse(true); + } } public ConnectivityService(Context context) { @@ -1064,13 +1100,15 @@ public class ConnectivityService extends IConnectivityManager.Stub mSystemProperties = mDeps.getSystemProperties(); mNetIdManager = mDeps.makeNetIdManager(); mContext = Objects.requireNonNull(context, "missing Context"); + mResources = deps.getResources(mContext); mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID); mMetricsLog = logger; mNetworkRanker = new NetworkRanker(); final NetworkRequest defaultInternetRequest = createDefaultRequest(); mDefaultRequest = new NetworkRequestInfo( - defaultInternetRequest, null, new Binder(), + defaultInternetRequest, null, + new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO, null /* attributionTags */); mNetworkRequests.put(defaultInternetRequest, mDefaultRequest); mDefaultNetworkRequests.add(mDefaultRequest); @@ -1124,8 +1162,6 @@ public class ConnectivityService extends IConnectivityManager.Stub final PowerManager powerManager = (PowerManager) context.getSystemService( Context.POWER_SERVICE); mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( - com.android.internal.R.integer.config_networkTransitionTimeout); mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1]; @@ -1192,10 +1228,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - mWolSupportedInterfaces = new ArraySet( - mContext.getResources().getStringArray( - com.android.internal.R.array.config_wakeonlan_supported_interfaces)); - mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mPermissionMonitor = new PermissionMonitor(mContext, mNetd); @@ -1246,8 +1278,7 @@ public class ConnectivityService extends IConnectivityManager.Stub new NetworkInfo(TYPE_NONE, 0, "", ""), new LinkProperties(), new NetworkCapabilities(), 0, mContext, null, new NetworkAgentConfig(), this, null, - null, 0, INVALID_UID, - mQosCallbackTracker); + null, 0, INVALID_UID, mQosCallbackTracker, mDeps); } private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) { @@ -1327,7 +1358,9 @@ public class ConnectivityService extends IConnectivityManager.Stub if (enable) { handleRegisterNetworkRequest(new NetworkRequestInfo( - networkRequest, null, new Binder(), + networkRequest, null, + new Binder(), + NetworkCallback.FLAG_INCLUDE_LOCATION_INFO, null /* attributionTags */)); } else { handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID, @@ -1489,11 +1522,11 @@ public class ConnectivityService extends IConnectivityManager.Stub // but only exists if an app asks about them or requests them. Ensure the requesting app // gets the type it asks for. filtered.setType(type); - final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked) - ? DetailedState.BLOCKED - : filtered.getDetailedState(); - filtered.setDetailedState(getLegacyLockdownState(state), - "" /* reason */, null /* extraInfo */); + if (isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)) { + filtered.setDetailedState(DetailedState.BLOCKED, null /* reason */, + null /* extraInfo */); + } + filterForLegacyLockdown(filtered); return filtered; } @@ -1569,8 +1602,8 @@ public class ConnectivityService extends IConnectivityManager.Stub final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, false) ? DetailedState.BLOCKED : DetailedState.DISCONNECTED; - info.setDetailedState(getLegacyLockdownState(state), - "" /* reason */, null /* extraInfo */); + info.setDetailedState(state, null /* reason */, null /* extraInfo */); + filterForLegacyLockdown(info); return info; } @@ -1688,8 +1721,8 @@ public class ConnectivityService extends IConnectivityManager.Stub result.put( nai.network, createWithLocationInfoSanitizedIfNecessaryWhenParceled( - nc, mDeps.getCallingUid(), callingPackageName, - callingAttributionTag)); + nc, false /* includeLocationSensitiveInfo */, + mDeps.getCallingUid(), callingPackageName, callingAttributionTag)); } } @@ -1702,7 +1735,9 @@ public class ConnectivityService extends IConnectivityManager.Stub result.put( network, createWithLocationInfoSanitizedIfNecessaryWhenParceled( - nc, mDeps.getCallingUid(), callingPackageName, + nc, + false /* includeLocationSensitiveInfo */, + mDeps.getCallingUid(), callingPackageName, callingAttributionTag)); } } @@ -1784,6 +1819,7 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceAccessPermission(); return createWithLocationInfoSanitizedIfNecessaryWhenParceled( getNetworkCapabilitiesInternal(network), + false /* includeLocationSensitiveInfo */, mDeps.getCallingUid(), callingPackageName, callingAttributionTag); } @@ -1817,8 +1853,8 @@ public class ConnectivityService extends IConnectivityManager.Stub @VisibleForTesting @Nullable NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled( - @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName, - @Nullable String callingAttributionTag) { + @Nullable NetworkCapabilities nc, boolean includeLocationSensitiveInfo, + int callerUid, @NonNull String callerPkgName, @Nullable String callingAttributionTag) { if (nc == null) { return null; } @@ -1826,7 +1862,9 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkCapabilities newNc; // Avoid doing location permission check if the transport info has no location sensitive // data. - if (nc.getTransportInfo() != null && nc.getTransportInfo().hasLocationSensitiveFields()) { + if (includeLocationSensitiveInfo + && nc.getTransportInfo() != null + && nc.getTransportInfo().hasLocationSensitiveFields()) { hasLocationPermission = hasLocationPermission(callerUid, callerPkgName, callingAttributionTag); newNc = new NetworkCapabilities(nc, hasLocationPermission); @@ -1843,6 +1881,16 @@ public class ConnectivityService extends IConnectivityManager.Stub // Owner UIDs already checked above. No need to re-check. return newNc; } + // If the caller does not want location sensitive data & target SDK >= S, then mask info. + // Else include the owner UID iff the caller has location permission to provide backwards + // compatibility for older apps. + if (!includeLocationSensitiveInfo + && isTargetSdkAtleast( + Build.VERSION_CODES.S, callerUid, callerPkgName)) { + newNc.setOwnerUid(INVALID_UID); + return newNc; + } + if (hasLocationPermission == null) { // Location permission not checked yet, check now for masking owner UID. hasLocationPermission = @@ -2364,9 +2412,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mContext.enforceCallingOrSelfPermission(KeepaliveTracker.PERMISSION, "ConnectivityService"); } - // Public because it's used by mLockdownTracker. - public void sendConnectedBroadcast(NetworkInfo info) { - PermissionUtils.enforceNetworkStackPermission(mContext); + private void sendConnectedBroadcast(NetworkInfo info) { sendGeneralBroadcast(info, CONNECTIVITY_ACTION); } @@ -2603,7 +2649,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) { - PriorityDump.dump(mPriorityDumper, fd, writer, args); + mPriorityDumper.dump(fd, writer, args); } private boolean checkDumpPermission(Context context, String tag, PrintWriter pw) { @@ -2618,10 +2664,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private void doDump(FileDescriptor fd, PrintWriter writer, String[] args, boolean asProto) { + private void doDump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); if (!checkDumpPermission(mContext, TAG, pw)) return; - if (asProto) return; if (CollectionUtils.contains(args, DIAG_ARG)) { dumpNetworkDiagnostics(pw); @@ -2864,22 +2909,6 @@ public class ConnectivityService extends IConnectivityManager.Stub super(looper); } - private boolean maybeHandleAsyncChannelMessage(Message msg) { - switch (msg.what) { - default: - return false; - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { - handleAsyncChannelHalfConnect(msg); - break; - } - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { - handleAsyncChannelDisconnected(msg); - break; - } - } - return true; - } - private void maybeHandleNetworkAgentMessage(Message msg) { final Pair<NetworkAgentInfo, Object> arg = (Pair<NetworkAgentInfo, Object>) msg.obj; final NetworkAgentInfo nai = arg.first; @@ -3171,8 +3200,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void handleMessage(Message msg) { - if (!maybeHandleAsyncChannelMessage(msg) - && !maybeHandleNetworkMonitorMessage(msg) + if (!maybeHandleNetworkMonitorMessage(msg) && !maybeHandleNetworkAgentInfoMessage(msg)) { maybeHandleNetworkAgentMessage(msg); } @@ -3436,21 +3464,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return false; } - private void handleAsyncChannelHalfConnect(Message msg) { - ensureRunningOnConnectivityServiceThread(); - if (mNetworkProviderInfos.containsKey(msg.replyTo)) { - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - if (VDBG) log("NetworkFactory connected"); - // Finish setting up the full connection - NetworkProviderInfo npi = mNetworkProviderInfos.get(msg.replyTo); - sendAllRequestsToProvider(npi); - } else { - loge("Error connecting NetworkFactory"); - mNetworkProviderInfos.remove(msg.obj); - } - } - } - private void handleNetworkAgentRegistered(Message msg) { final NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj; if (!mNetworkAgentInfos.contains(nai)) { @@ -3481,14 +3494,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - // This is a no-op if it's called with a message designating a provider that has - // already been destroyed, because its reference will not be found in the relevant - // maps. - private void handleAsyncChannelDisconnected(Message msg) { - NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo); - if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name); - } - // Destroys a network, remove references to it from the internal state managed by // ConnectivityService, free its interfaces and clean up. // Must be called on the Handler thread. @@ -4597,7 +4602,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } mWakelockLogs.log("ACQUIRE for " + forWhom); Message msg = mHandler.obtainMessage(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK); - mHandler.sendMessageDelayed(msg, mNetTransitionWakeLockTimeout); + final int lockTimeout = mResources.get().getInteger( + com.android.connectivity.resources.R.integer.config_networkTransitionTimeout); + mHandler.sendMessageDelayed(msg, lockTimeout); } // Called when we gain a new default network to release the network transition wakelock in a @@ -5012,8 +5019,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // The legacy lockdown VPN always uses the default network. // If the VPN's underlying network is no longer the current default network, it means that // the default network has just switched, and the VPN is about to disconnect. - // Report that the VPN is not connected, so when the state of NetworkInfo objects - // overwritten by getLegacyLockdownState will be set to CONNECTING and not CONNECTED. + // Report that the VPN is not connected, so the state of NetworkInfo objects overwritten + // by filterForLegacyLockdown will be set to CONNECTING and not CONNECTED. final NetworkAgentInfo defaultNetwork = getDefaultNetwork(); if (defaultNetwork == null || !defaultNetwork.network.equals(underlying[0])) { return null; @@ -5022,6 +5029,9 @@ public class ConnectivityService extends IConnectivityManager.Stub return nai; }; + // TODO: move all callers to filterForLegacyLockdown and delete this method. + // This likely requires making sendLegacyNetworkBroadcast take a NetworkInfo object instead of + // just a DetailedState object. private DetailedState getLegacyLockdownState(DetailedState origState) { if (origState != DetailedState.CONNECTED) { return origState; @@ -5031,6 +5041,23 @@ public class ConnectivityService extends IConnectivityManager.Stub : DetailedState.CONNECTED; } + private void filterForLegacyLockdown(NetworkInfo ni) { + if (!mLockdownEnabled || !ni.isConnected()) return; + // The legacy lockdown VPN replaces the state of every network in CONNECTED state with the + // state of its VPN. This is to ensure that when an underlying network connects, apps will + // not see a CONNECTIVITY_ACTION broadcast for a network in state CONNECTED until the VPN + // comes up, at which point there is a new CONNECTIVITY_ACTION broadcast for the underlying + // network, this time with a state of CONNECTED. + // + // Now that the legacy lockdown code lives in ConnectivityService, and no longer has access + // to the internal state of the Vpn object, always replace the state with CONNECTING. This + // is not too far off the truth, since an always-on VPN, when not connected, is always + // trying to reconnect. + if (getLegacyLockdownNai() == null) { + ni.setDetailedState(DetailedState.CONNECTING, "", null); + } + } + @Override public void setProvisioningNotificationVisible(boolean visible, int networkType, String action) { @@ -5109,8 +5136,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private final IBinder.DeathRecipient mDeathRecipient; public final int providerId; - NetworkProviderInfo(String name, Messenger messenger, AsyncChannel asyncChannel, - int providerId, @NonNull IBinder.DeathRecipient deathRecipient) { + NetworkProviderInfo(String name, Messenger messenger, int providerId, + @NonNull IBinder.DeathRecipient deathRecipient) { this.name = name; this.messenger = messenger; this.providerId = providerId; @@ -5204,6 +5231,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private final IBinder mBinder; final int mPid; final int mUid; + final @NetworkCallback.Flag int mCallbackFlags; @Nullable final String mCallingAttributionTag; // In order to preserve the mapping of NetworkRequest-to-callback when apps register @@ -5251,17 +5279,26 @@ public class ConnectivityService extends IConnectivityManager.Stub mPid = getCallingPid(); mUid = mDeps.getCallingUid(); mNetworkRequestCounter.incrementCountOrThrow(mUid); + /** + * Location sensitive data not included in pending intent. Only included in + * {@link NetworkCallback}. + */ + mCallbackFlags = NetworkCallback.FLAG_NONE; mCallingAttributionTag = callingAttributionTag; } NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m, - @Nullable final IBinder binder, @Nullable String callingAttributionTag) { - this(Collections.singletonList(r), r, m, binder, callingAttributionTag); + @Nullable final IBinder binder, + @NetworkCallback.Flag int callbackFlags, + @Nullable String callingAttributionTag) { + this(Collections.singletonList(r), r, m, binder, callbackFlags, callingAttributionTag); } NetworkRequestInfo(@NonNull final List<NetworkRequest> r, @NonNull final NetworkRequest requestForCallback, @Nullable final Messenger m, - @Nullable final IBinder binder, @Nullable String callingAttributionTag) { + @Nullable final IBinder binder, + @NetworkCallback.Flag int callbackFlags, + @Nullable String callingAttributionTag) { super(); ensureAllNetworkRequestsHaveType(r); mRequests = initializeRequests(r); @@ -5272,6 +5309,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mUid = mDeps.getCallingUid(); mPendingIntent = null; mNetworkRequestCounter.incrementCountOrThrow(mUid); + mCallbackFlags = callbackFlags; mCallingAttributionTag = callingAttributionTag; try { @@ -5313,6 +5351,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mUid = nri.mUid; mPendingIntent = nri.mPendingIntent; mNetworkRequestCounter.incrementCountOrThrow(mUid); + mCallbackFlags = nri.mCallbackFlags; mCallingAttributionTag = nri.mCallingAttributionTag; } @@ -5362,7 +5401,8 @@ public class ConnectivityService extends IConnectivityManager.Stub + " callback request Id: " + mNetworkRequestForCallback.requestId + " " + mRequests - + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent); + + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent) + + "callback flags: " + mCallbackFlags; } } @@ -5446,13 +5486,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private boolean checkUnsupportedStartingFrom(int version, String callingPackageName) { - final UserHandle user = UserHandle.getUserHandleForUid(mDeps.getCallingUid()); + private boolean isTargetSdkAtleast(int version, int callingUid, + @NonNull String callingPackageName) { + final UserHandle user = UserHandle.getUserHandleForUid(callingUid); final PackageManager pm = mContext.createContextAsUser(user, 0 /* flags */).getPackageManager(); try { - final int callingVersion = pm.getApplicationInfo( - callingPackageName, 0 /* flags */).targetSdkVersion; + final int callingVersion = pm.getTargetSdkVersion(callingPackageName); if (callingVersion < version) return false; } catch (PackageManager.NameNotFoundException e) { } return true; @@ -5461,10 +5501,11 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder, - int legacyType, @NonNull String callingPackageName, + int legacyType, int callbackFlags, @NonNull String callingPackageName, @Nullable String callingAttributionTag) { if (legacyType != TYPE_NONE && !checkNetworkStackPermission()) { - if (checkUnsupportedStartingFrom(Build.VERSION_CODES.M, callingPackageName)) { + if (isTargetSdkAtleast(Build.VERSION_CODES.M, mDeps.getCallingUid(), + callingPackageName)) { throw new SecurityException("Insufficient permissions to specify legacy type"); } } @@ -5501,6 +5542,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // request if the app changes network state. http://b/29964605 enforceMeteredApnPolicy(networkCapabilities); break; + case TRACK_BEST: + throw new UnsupportedOperationException("Not implemented yet"); default: throw new IllegalArgumentException("Unsupported request type " + reqType); } @@ -5524,7 +5567,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, nextNetworkRequestId(), reqType); final NetworkRequestInfo nri = getNriToRegister( - networkRequest, messenger, binder, callingAttributionTag); + networkRequest, messenger, binder, callbackFlags, callingAttributionTag); if (DBG) log("requestNetwork for " + nri); // For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were @@ -5559,6 +5602,7 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private NetworkRequestInfo getNriToRegister(@NonNull final NetworkRequest nr, @Nullable final Messenger msgr, @Nullable final IBinder binder, + @NetworkCallback.Flag int callbackFlags, @Nullable String callingAttributionTag) { final List<NetworkRequest> requests; if (NetworkRequest.Type.TRACK_DEFAULT == nr.type) { @@ -5567,7 +5611,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } else { requests = Collections.singletonList(nr); } - return new NetworkRequestInfo(requests, nr, msgr, binder, callingAttributionTag); + return new NetworkRequestInfo( + requests, nr, msgr, binder, callbackFlags, callingAttributionTag); } private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities, @@ -5693,8 +5738,9 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities, - Messenger messenger, IBinder binder, @NonNull String callingPackageName, - @Nullable String callingAttributionTag) { + Messenger messenger, IBinder binder, + @NetworkCallback.Flag int callbackFlags, + @NonNull String callingPackageName, @NonNull String callingAttributionTag) { final int callingUid = mDeps.getCallingUid(); if (!hasWifiNetworkListenPermission(networkCapabilities)) { enforceAccessPermission(); @@ -5715,7 +5761,8 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN); NetworkRequestInfo nri = - new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag); + new NetworkRequestInfo(networkRequest, messenger, binder, callbackFlags, + callingAttributionTag); if (VDBG) log("listenForNetwork for " + nri); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri)); @@ -5784,8 +5831,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public int registerNetworkProvider(Messenger messenger, String name) { enforceNetworkFactoryOrSettingsPermission(); NetworkProviderInfo npi = new NetworkProviderInfo(name, messenger, - null /* asyncChannel */, nextNetworkProviderId(), - () -> unregisterNetworkProvider(messenger)); + nextNetworkProviderId(), () -> unregisterNetworkProvider(messenger)); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_PROVIDER, npi)); return npi.providerId; } @@ -6106,7 +6152,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkAgentInfo nai = new NetworkAgentInfo(na, new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig), - this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker); + this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker, mDeps); // Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says. processCapabilitiesFromAgent(nai, nc); @@ -6472,6 +6518,11 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void updateWakeOnLan(@NonNull LinkProperties lp) { + if (mWolSupportedInterfaces == null) { + mWolSupportedInterfaces = new ArraySet<>(mResources.get().getStringArray( + com.android.connectivity.resources.R.array + .config_wakeonlan_supported_interfaces)); + } lp.setWakeOnLanSupported(mWolSupportedInterfaces.contains(lp.getInterfaceName())); } @@ -7044,6 +7095,8 @@ public class ConnectivityService extends IConnectivityManager.Stub if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) { putParcelable(bundle, networkAgent.network); } + final boolean includeLocationSensitiveInfo = + (nri.mCallbackFlags & NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) != 0; switch (notificationType) { case ConnectivityManager.CALLBACK_AVAILABLE: { final NetworkCapabilities nc = @@ -7052,7 +7105,8 @@ public class ConnectivityService extends IConnectivityManager.Stub putParcelable( bundle, createWithLocationInfoSanitizedIfNecessaryWhenParceled( - nc, nri.mUid, nrForCallback.getRequestorPackageName(), + nc, includeLocationSensitiveInfo, nri.mUid, + nrForCallback.getRequestorPackageName(), nri.mCallingAttributionTag)); putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions( networkAgent.linkProperties, nri.mPid, nri.mUid)); @@ -7072,7 +7126,8 @@ public class ConnectivityService extends IConnectivityManager.Stub putParcelable( bundle, createWithLocationInfoSanitizedIfNecessaryWhenParceled( - netCap, nri.mUid, nrForCallback.getRequestorPackageName(), + netCap, includeLocationSensitiveInfo, nri.mUid, + nrForCallback.getRequestorPackageName(), nri.mCallingAttributionTag)); break; } @@ -7914,6 +7969,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // and is still connected. NetworkInfo info = new NetworkInfo(nai.networkInfo); info.setType(type); + filterForLegacyLockdown(info); if (state != DetailedState.DISCONNECTED) { info.setDetailedState(state, null, info.getExtraInfo()); sendConnectedBroadcast(info); @@ -8028,8 +8084,8 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public String getCaptivePortalServerUrl() { enforceNetworkStackOrSettingsPermission(); - String settingUrl = mContext.getResources().getString( - R.string.config_networkCaptivePortalServerUrl); + String settingUrl = mResources.get().getString( + com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl); if (!TextUtils.isEmpty(settingUrl)) { return settingUrl; diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java index b9922087109f..2465479aadd8 100644 --- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java +++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java @@ -16,9 +16,6 @@ package com.android.server; -import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; -import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; - import android.content.Context; import android.util.Log; @@ -42,6 +39,6 @@ public final class ConnectivityServiceInitializer extends SystemService { public void onStart() { Log.i(TAG, "Registering " + Context.CONNECTIVITY_SERVICE); publishBinderService(Context.CONNECTIVITY_SERVICE, mConnectivity, - /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL); + /* allowIsolated= */ false); } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 81d4b9da63c8..4c3c6ef21fc5 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -56,6 +56,7 @@ import android.system.Os; import android.system.OsConstants; import android.text.TextUtils; import android.util.Log; +import android.util.Range; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -756,13 +757,9 @@ public class IpSecService extends IIpSecService.Stub { } } - // These values have been reserved in NetIdManager - @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00; - - public static final int TUN_INTF_NETID_RANGE = 0x0400; - private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray(); - private int mNextTunnelNetIdIndex = 0; + final Range<Integer> mNetIdRange = ConnectivityManager.getIpSecNetIdRange(); + private int mNextTunnelNetId = mNetIdRange.getLower(); /** * Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces @@ -775,11 +772,13 @@ public class IpSecService extends IIpSecService.Stub { */ @VisibleForTesting int reserveNetId() { + final int range = mNetIdRange.getUpper() - mNetIdRange.getLower() + 1; synchronized (mTunnelNetIds) { - for (int i = 0; i < TUN_INTF_NETID_RANGE; i++) { - int index = mNextTunnelNetIdIndex; - int netId = index + TUN_INTF_NETID_START; - if (++mNextTunnelNetIdIndex >= TUN_INTF_NETID_RANGE) mNextTunnelNetIdIndex = 0; + for (int i = 0; i < range; i++) { + final int netId = mNextTunnelNetId; + if (++mNextTunnelNetId > mNetIdRange.getUpper()) { + mNextTunnelNetId = mNetIdRange.getLower(); + } if (!mTunnelNetIds.get(netId)) { mTunnelNetIds.put(netId, true); return netId; diff --git a/services/core/java/com/android/server/NetIdManager.java b/services/core/java/com/android/server/NetIdManager.java index 097fb3ae47e3..61925c80a22b 100644 --- a/services/core/java/com/android/server/NetIdManager.java +++ b/services/core/java/com/android/server/NetIdManager.java @@ -17,6 +17,7 @@ package com.android.server; import android.annotation.NonNull; +import android.net.ConnectivityManager; import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; @@ -31,7 +32,7 @@ public class NetIdManager { // Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp public static final int MIN_NET_ID = 100; // some reserved marks // Top IDs reserved by IpSecService - public static final int MAX_NET_ID = 65535 - IpSecService.TUN_INTF_NETID_RANGE; + public static final int MAX_NET_ID = ConnectivityManager.getIpSecNetIdRange().getLower() - 1; @GuardedBy("mNetIdInUse") private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray(); diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java index f2782f64995a..18d47c6fb7b3 100644 --- a/services/core/java/com/android/server/SensorPrivacyService.java +++ b/services/core/java/com/android/server/SensorPrivacyService.java @@ -51,6 +51,7 @@ import android.graphics.drawable.Icon; import android.hardware.ISensorPrivacyListener; import android.hardware.ISensorPrivacyManager; import android.hardware.SensorPrivacyManager; +import android.hardware.SensorPrivacyManagerInternal; import android.os.Binder; import android.os.Environment; import android.os.Handler; @@ -67,6 +68,7 @@ import android.service.SensorPrivacyServiceDumpProto; import android.service.SensorPrivacyUserProto; import android.text.Html; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.AtomicFile; import android.util.IndentingPrintWriter; import android.util.Log; @@ -80,6 +82,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.internal.util.FunctionalUtils; import com.android.internal.util.XmlUtils; @@ -137,6 +140,8 @@ public final class SensorPrivacyService extends SystemService { private final ActivityManager mActivityManager; private final ActivityTaskManager mActivityTaskManager; + private SensorPrivacyManagerInternalImpl mSensorPrivacyManagerInternal; + public SensorPrivacyService(Context context) { super(context); mUserManagerInternal = getLocalService(UserManagerInternal.class); @@ -148,6 +153,9 @@ public final class SensorPrivacyService extends SystemService { @Override public void onStart() { publishBinderService(Context.SENSOR_PRIVACY_SERVICE, mSensorPrivacyServiceImpl); + mSensorPrivacyManagerInternal = new SensorPrivacyManagerInternalImpl(); + publishLocalService(SensorPrivacyManagerInternal.class, + mSensorPrivacyManagerInternal); } class SensorPrivacyServiceImpl extends ISensorPrivacyManager.Stub implements @@ -1108,6 +1116,7 @@ public final class SensorPrivacyService extends SystemService { } public void handleSensorPrivacyChanged(int userId, int sensor, boolean enabled) { + mSensorPrivacyManagerInternal.dispatch(userId, sensor, enabled); SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser = mIndividualSensorListeners.get(userId); if (listenersForUser == null) { @@ -1168,4 +1177,87 @@ public final class SensorPrivacyService extends SystemService { c.accept(userIds[i]); } } + + private class SensorPrivacyManagerInternalImpl extends SensorPrivacyManagerInternal { + + private ArrayMap<Integer, ArrayMap<Integer, ArraySet<OnSensorPrivacyChangedListener>>> + mListeners = new ArrayMap<>(); + private ArrayMap<Integer, ArraySet<OnUserSensorPrivacyChangedListener>> mAllUserListeners = + new ArrayMap<>(); + + private final Object mLock = new Object(); + + private void dispatch(int userId, int sensor, boolean enabled) { + synchronized (mLock) { + ArraySet<OnUserSensorPrivacyChangedListener> allUserSensorListeners = + mAllUserListeners.get(sensor); + if (allUserSensorListeners != null) { + for (int i = 0; i < allUserSensorListeners.size(); i++) { + OnUserSensorPrivacyChangedListener listener = + allUserSensorListeners.valueAt(i); + BackgroundThread.getHandler().post(() -> + listener.onSensorPrivacyChanged(userId, enabled)); + } + } + + ArrayMap<Integer, ArraySet<OnSensorPrivacyChangedListener>> userSensorListeners = + mListeners.get(userId); + if (userSensorListeners != null) { + ArraySet<OnSensorPrivacyChangedListener> sensorListeners = + userSensorListeners.get(sensor); + if (sensorListeners != null) { + for (int i = 0; i < sensorListeners.size(); i++) { + OnSensorPrivacyChangedListener listener = sensorListeners.valueAt(i); + BackgroundThread.getHandler().post(() -> + listener.onSensorPrivacyChanged(enabled)); + } + } + } + } + } + + @Override + public boolean isSensorPrivacyEnabled(int userId, int sensor) { + return SensorPrivacyService.this + .mSensorPrivacyServiceImpl.isIndividualSensorPrivacyEnabled(userId, sensor); + } + + @Override + public void addSensorPrivacyListener(int userId, int sensor, + OnSensorPrivacyChangedListener listener) { + synchronized (mLock) { + ArrayMap<Integer, ArraySet<OnSensorPrivacyChangedListener>> userSensorListeners = + mListeners.get(userId); + if (userSensorListeners == null) { + userSensorListeners = new ArrayMap<>(); + mListeners.put(userId, userSensorListeners); + } + + ArraySet<OnSensorPrivacyChangedListener> sensorListeners = + userSensorListeners.get(sensor); + if (sensorListeners == null) { + sensorListeners = new ArraySet<>(); + userSensorListeners.put(sensor, sensorListeners); + } + + sensorListeners.add(listener); + } + } + + @Override + public void addSensorPrivacyListenerForAllUsers(int sensor, + OnUserSensorPrivacyChangedListener listener) { + synchronized (mLock) { + ArraySet<OnUserSensorPrivacyChangedListener> sensorListeners = + mAllUserListeners.get(sensor); + if (sensorListeners == null) { + sensorListeners = new ArraySet<>(); + mAllUserListeners.put(sensor, sensorListeners); + } + + sensorListeners.add(listener); + } + } + } + } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 27b648e53a38..740a1c16a486 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -4553,6 +4553,13 @@ class StorageManagerService extends IStorageManager.Stub private final List<StorageManagerInternal.ResetListener> mResetListeners = new ArrayList<>(); + @Override + public boolean isFuseMounted(int userId) { + synchronized (mLock) { + return mFuseMountedUser.contains(userId); + } + } + /** * Check if fuse is running in target user, if it's running then setup its storage dirs. * Return true if storage dirs are mounted. diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING index 95af84293377..a09dbc7e599d 100644 --- a/services/core/java/com/android/server/TEST_MAPPING +++ b/services/core/java/com/android/server/TEST_MAPPING @@ -21,7 +21,9 @@ } ], "file_patterns": ["NotificationManagerService\\.java"] - }, + } + ], + "presubmit-large": [ { "name": "CtsScopedStorageCoreHostTest", "file_patterns": ["StorageManagerService\\.java"] diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 978bd643f9b7..a9904ba0de91 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -964,14 +964,21 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { remove(r.binder); } } - if (events.contains(TelephonyCallback.EVENT_CALL_STATE_CHANGED)) { + if (events.contains(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED)) { try { - r.callback.onCallStateChanged(mCallState[phoneId], + r.callback.onLegacyCallStateChanged(mCallState[phoneId], getCallIncomingNumber(r, phoneId)); } catch (RemoteException ex) { remove(r.binder); } } + if (events.contains(TelephonyCallback.EVENT_CALL_STATE_CHANGED)) { + try { + r.callback.onCallStateChanged(mCallState[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); + } + } if (events.contains(TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)) { try { r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId], @@ -1306,13 +1313,24 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { synchronized (mRecords) { for (Record r : mRecords) { - if (r.matchTelephonyCallbackEvent(TelephonyCallback.EVENT_CALL_STATE_CHANGED) + if (r.matchTelephonyCallbackEvent(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED) && (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) { try { // Ensure the listener has read call log permission; if they do not return // an empty phone number. + // This is ONLY for legacy onCallStateChanged in PhoneStateListener. String phoneNumberOrEmpty = r.canReadCallLog() ? phoneNumber : ""; - r.callback.onCallStateChanged(state, phoneNumberOrEmpty); + r.callback.onLegacyCallStateChanged(state, phoneNumberOrEmpty); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + + if (r.matchTelephonyCallbackEvent(TelephonyCallback.EVENT_CALL_STATE_CHANGED) + && (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) { + try { + // The new callback does NOT provide the phone number. + r.callback.onCallStateChanged(state); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -1341,12 +1359,25 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallState[phoneId] = state; mCallIncomingNumber[phoneId] = incomingNumber; for (Record r : mRecords) { - if (r.matchTelephonyCallbackEvent(TelephonyCallback.EVENT_CALL_STATE_CHANGED) + if (r.matchTelephonyCallbackEvent( + TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED) && (r.subId == subId) && (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) { try { + // Only the legacy PhoneStateListener receives the phone number. String incomingNumberOrEmpty = getCallIncomingNumber(r, phoneId); - r.callback.onCallStateChanged(state, incomingNumberOrEmpty); + r.callback.onLegacyCallStateChanged(state, incomingNumberOrEmpty); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + if (r.matchTelephonyCallbackEvent(TelephonyCallback.EVENT_CALL_STATE_CHANGED) + && (r.subId == subId) + && (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) { + try { + // The phone number is not included in the new call state changed + // listener. + r.callback.onCallStateChanged(state); } catch (RemoteException ex) { mRemoveList.add(r.binder); } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index f768db1d0821..68c4a7336745 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -20,7 +20,6 @@ import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND; import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT; -import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT; import static android.app.ActivityManager.PROCESS_STATE_RECEIVER; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -75,7 +74,6 @@ import android.app.ActivityManagerInternal; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppOpsManager; -import android.app.BroadcastOptions; import android.app.ForegroundServiceStartNotAllowedException; import android.app.IApplicationThread; import android.app.IServiceConnection; @@ -1217,7 +1215,18 @@ public final class ActiveServices { void killMisbehavingService(ServiceRecord r, int appUid, int appPid, String localPackageName) { synchronized (mAm) { - stopServiceLocked(r, false); + if (!r.destroying) { + // This service is still alive, stop it. + stopServiceLocked(r, false); + } else { + // Check if there is another instance of it being started in parallel, + // if so, stop that too to avoid spamming the system. + final ServiceMap smap = getServiceMapLocked(r.userId); + final ServiceRecord found = smap.mServicesByInstanceName.remove(r.instanceName); + if (found != null) { + stopServiceLocked(found, false); + } + } mAm.crashApplication(appUid, appPid, localPackageName, -1, "Bad notification for startForeground", true /*force*/); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8ea6194a9535..06a1abb72607 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -44,11 +44,11 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.FactoryTest.FACTORY_TEST_OFF; -import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; import static android.os.IServiceManager.DUMP_FLAG_PROTO; +import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED; import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; import static android.os.Process.BLUETOOTH_UID; @@ -273,6 +273,9 @@ import android.os.TransactionTooLargeException; import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; +import android.os.incremental.IIncrementalService; +import android.os.incremental.IncrementalManager; +import android.os.incremental.IncrementalMetrics; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.provider.DeviceConfig; @@ -7697,18 +7700,32 @@ public class ActivityManagerService extends IActivityManager.Stub */ void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName, ApplicationErrorReport.CrashInfo crashInfo) { - boolean isPackageLoading = false; + boolean isIncremental = false; + float loadingProgress = 1; + long millisSinceOldestPendingRead = 0; // Notify package manager service to possibly update package state if (r != null && r.info != null && r.info.packageName != null) { + final String codePath = r.info.getCodePath(); mPackageManagerInt.notifyPackageCrashOrAnr(r.info.packageName); IncrementalStatesInfo incrementalStatesInfo = mPackageManagerInt.getIncrementalStatesInfo(r.info.packageName, r.uid, r.userId); - isPackageLoading = incrementalStatesInfo.isLoading(); - if (isPackageLoading) { - // Report in the main log that the package is still loading - Slog.e(TAG, "App crashed when package " + r.info.packageName + " is " - + ((int) (incrementalStatesInfo.getProgress() * 100)) + "% loaded."); + if (incrementalStatesInfo != null) { + loadingProgress = incrementalStatesInfo.getProgress(); + } + isIncremental = IncrementalManager.isIncrementalPath(codePath); + if (isIncremental) { + // Report in the main log about the incremental package + Slog.e(TAG, "App crashed on incremental package " + r.info.packageName + + " which is " + ((int) (loadingProgress * 100)) + "% loaded."); + final IBinder incrementalService = ServiceManager.getService( + Context.INCREMENTAL_SERVICE); + if (incrementalService != null) { + final IncrementalManager incrementalManager = new IncrementalManager( + IIncrementalService.Stub.asInterface(incrementalService)); + IncrementalMetrics metrics = incrementalManager.getMetrics(codePath); + millisSinceOldestPendingRead = metrics.getMillisSinceOldestPendingRead(); + } } } @@ -7737,7 +7754,7 @@ public class ActivityManagerService extends IActivityManager.Stub processName.equals("system_server") ? ServerProtoEnums.SYSTEM_SERVER : (r != null) ? r.getProcessClassEnum() : ServerProtoEnums.ERROR_SOURCE_UNKNOWN, - isPackageLoading + isIncremental, loadingProgress, millisSinceOldestPendingRead ); final int relaunchReason = r == null ? RELAUNCH_REASON_NONE diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index dbfa7f34c6f9..6b9fc0718879 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -32,6 +32,7 @@ import android.net.ConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.Network; import android.net.NetworkCapabilities; +import android.os.BatteryManagerInternal; import android.os.BatteryStats; import android.os.BatteryStatsInternal; import android.os.BatteryUsageStats; @@ -184,6 +185,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub } }; + private BatteryManagerInternal mBatteryManagerInternal; + private void populatePowerEntityMaps() { PowerEntity[] entities = mPowerStatsInternal.getPowerEntityInfo(); if (entities == null) { @@ -370,6 +373,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub Slog.e(TAG, "Could not register PowerStatsInternal"); } } + mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class); Watchdog.getInstance().addMonitor(this); @@ -2715,4 +2719,44 @@ public final class BatteryStatsService extends IBatteryStats.Stub }); } } + + /** + * Sets battery AC charger to enabled/disabled, and freezes the battery state. + */ + @Override + public void setChargerAcOnline(boolean online, boolean forceUpdate) { + mBatteryManagerInternal.setChargerAcOnline(online, forceUpdate); + } + + /** + * Sets battery level, and freezes the battery state. + */ + @Override + public void setBatteryLevel(int level, boolean forceUpdate) { + mBatteryManagerInternal.setBatteryLevel(level, forceUpdate); + } + + /** + * Unplugs battery, and freezes the battery state. + */ + @Override + public void unplugBattery(boolean forceUpdate) { + mBatteryManagerInternal.unplugBattery(forceUpdate); + } + + /** + * Unfreezes battery state, returning to current hardware values. + */ + @Override + public void resetBattery(boolean forceUpdate) { + mBatteryManagerInternal.resetBattery(forceUpdate); + } + + /** + * Suspend charging even if plugged in. + */ + @Override + public void suspendBatteryInput() { + mBatteryManagerInternal.suspendBatteryInput(); + } } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 81c4c8605fb4..e79f09665153 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -1416,7 +1416,7 @@ public final class BroadcastQueue { } } if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID && - r.requiredPermissions != null && r.requiredPermissions.length > 0) { + r.requiredPermissions != null && r.requiredPermissions.length > 0) { for (int i = 0; i < r.requiredPermissions.length; i++) { String requiredPermission = r.requiredPermissions[i]; try { @@ -1424,7 +1424,7 @@ public final class BroadcastQueue { checkPermission(requiredPermission, info.activityInfo.applicationInfo.packageName, UserHandle - .getUserId(info.activityInfo.applicationInfo.uid)); + .getUserId(info.activityInfo.applicationInfo.uid)); } catch (RemoteException e) { perm = PackageManager.PERMISSION_DENIED; } @@ -1439,36 +1439,18 @@ public final class BroadcastQueue { break; } int appOp = AppOpsManager.permissionToOpCode(requiredPermission); - if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp - && mService.getAppOpsManager().noteOpNoThrow(appOp, - info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, - null /* default featureId */, - "Broadcast delivered to " + info.activityInfo.name) - != AppOpsManager.MODE_ALLOWED) { - Slog.w(TAG, "Appop Denial: receiving " - + r.intent + " to " - + component.flattenToShortString() - + " requires appop " + AppOpsManager.permissionToOp( - requiredPermission) - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")"); - skip = true; - break; + if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp) { + if (!noteOpForManifestReceiver(appOp, r, info, component)) { + skip = true; + break; + } } } } - if (!skip && r.appOp != AppOpsManager.OP_NONE - && mService.getAppOpsManager().noteOpNoThrow(r.appOp, - info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, - null /* default featureId */, "Broadcast delivered to " + info.activityInfo.name) - != AppOpsManager.MODE_ALLOWED) { - Slog.w(TAG, "Appop Denial: receiving " - + r.intent + " to " - + component.flattenToShortString() - + " requires appop " + AppOpsManager.opToName(r.appOp) - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")"); - skip = true; + if (!skip && r.appOp != AppOpsManager.OP_NONE) { + if (!noteOpForManifestReceiver(r.appOp, r, info, component)) { + skip = true; + } } boolean isSingleton = false; try { @@ -1717,6 +1699,40 @@ public final class BroadcastQueue { mPendingBroadcastRecvIndex = recIdx; } + private boolean noteOpForManifestReceiver(int appOp, BroadcastRecord r, ResolveInfo info, + ComponentName component) { + if (info.activityInfo.attributionTags == null) { + return noteOpForManifestReceiverInner(appOp, r, info, component, null); + } else { + // Attribution tags provided, noteOp each tag + for (String tag : info.activityInfo.attributionTags) { + if (!noteOpForManifestReceiverInner(appOp, r, info, component, tag)) { + return false; + } + } + return true; + } + } + + private boolean noteOpForManifestReceiverInner(int appOp, BroadcastRecord r, ResolveInfo info, + ComponentName component, String tag) { + if (mService.getAppOpsManager().noteOpNoThrow(appOp, + info.activityInfo.applicationInfo.uid, + info.activityInfo.packageName, + tag, + "Broadcast delivered to " + info.activityInfo.name) + != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: receiving " + + r.intent + " to " + + component.flattenToShortString() + + " requires appop " + AppOpsManager.opToName(appOp) + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + return false; + } + return true; + } + private void maybeAddAllowBackgroundActivityStartsToken(ProcessRecord proc, BroadcastRecord r) { if (r == null || proc == null || !r.allowBackgroundActivityStarts) { return; diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java index d03a47afed8a..93f30cc8ac5e 100644 --- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java @@ -26,12 +26,18 @@ import android.app.AnrController; import android.app.ApplicationErrorReport; import android.app.ApplicationExitInfo; import android.content.ComponentName; +import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IncrementalStatesInfo; import android.content.pm.PackageManagerInternal; +import android.os.IBinder; import android.os.Message; import android.os.Process; +import android.os.ServiceManager; import android.os.SystemClock; +import android.os.incremental.IIncrementalService; +import android.os.incremental.IncrementalManager; +import android.os.incremental.IncrementalMetrics; import android.provider.Settings; import android.util.EventLog; import android.util.Slog; @@ -294,14 +300,31 @@ class ProcessErrorStateRecord { } // Check if package is still being loaded - boolean isPackageLoading = false; + boolean isIncremental = false; + float loadingProgress = 1; + long millisSinceOldestPendingRead = 0; final PackageManagerInternal packageManagerInternal = mService.getPackageManagerInternal(); if (aInfo != null && aInfo.packageName != null) { IncrementalStatesInfo incrementalStatesInfo = packageManagerInternal.getIncrementalStatesInfo( aInfo.packageName, mApp.uid, mApp.userId); if (incrementalStatesInfo != null) { - isPackageLoading = incrementalStatesInfo.isLoading(); + loadingProgress = incrementalStatesInfo.getProgress(); + } + final String codePath = aInfo.getCodePath(); + isIncremental = IncrementalManager.isIncrementalPath(codePath); + if (isIncremental) { + // Report in the main log that the incremental package is still loading + Slog.e(TAG, "App crashed on incremental package " + aInfo.packageName + + " which is " + ((int) (loadingProgress * 100)) + "% loaded."); + final IBinder incrementalService = ServiceManager.getService( + Context.INCREMENTAL_SERVICE); + if (incrementalService != null) { + final IncrementalManager incrementalManager = new IncrementalManager( + IIncrementalService.Stub.asInterface(incrementalService)); + IncrementalMetrics metrics = incrementalManager.getMetrics(codePath); + millisSinceOldestPendingRead = metrics.getMillisSinceOldestPendingRead(); + } } } @@ -322,10 +345,8 @@ class ProcessErrorStateRecord { info.append("Parent: ").append(parentShortComponentName).append("\n"); } - if (isPackageLoading) { - // Report in the main log that the package is still loading - final float loadingProgress = packageManagerInternal.getIncrementalStatesInfo( - aInfo.packageName, mApp.uid, mApp.userId).getProgress(); + if (isIncremental) { + // Report in the main log about the incremental package info.append("Package is ").append((int) (loadingProgress * 100)).append("% loaded.\n"); } @@ -412,7 +433,8 @@ class ProcessErrorStateRecord { ? FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND : FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND, mApp.getProcessClassEnum(), - (mApp.info != null) ? mApp.info.packageName : "", isPackageLoading); + (mApp.info != null) ? mApp.info.packageName : "", + isIncremental, loadingProgress, millisSinceOldestPendingRead); 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 38330fe770fb..ed8d696f98c4 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -2315,11 +2315,12 @@ public final class ProcessList { StorageManagerInternal storageManagerInternal = LocalServices.getService( StorageManagerInternal.class); if (needsStorageDataIsolation(storageManagerInternal, app)) { - bindMountAppStorageDirs = true; - if (pkgDataInfoMap == null || - !storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(), - app.processName)) { - // Cannot prepare Android/app and Android/obb directory or inode == 0, + // We will run prepareStorageDirs() after we trigger zygote fork, so it won't + // slow down app starting speed as those dirs might not be cached. + if (pkgDataInfoMap != null && storageManagerInternal.isFuseMounted(userId)) { + bindMountAppStorageDirs = true; + } else { + // Fuse is not mounted or inode == 0, // so we won't mount it in zygote, but resume the mount after unlocking device. app.setBindMountPending(true); bindMountAppStorageDirs = false; @@ -2367,6 +2368,13 @@ public final class ProcessList { allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs, new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()}); } + // This runs after Process.start() as this method may block app process starting time + // if dir is not cached. Running this method after Process.start() can make it + // cache the dir asynchronously, so zygote can use it without waiting for it. + if (bindMountAppStorageDirs) { + storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(), + app.processName); + } checkSlow(startTime, "startProcess: returned from zygote!"); return startResult; } finally { diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index caf2510e5b1c..ec2020f94969 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -122,7 +122,6 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; /** * Helper class for {@link ActivityManagerService} responsible for multi-user functionality. @@ -518,18 +517,12 @@ class UserController implements Handler.Callback { if (!mInjector.getUserManager().isPreCreated(userId)) { mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG, userId, 0)); - Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null); - intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); - intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT - | Intent.FLAG_RECEIVER_OFFLOAD - | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - mInjector.broadcastIntent(intent, null, resultTo, 0, null, null, - new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, - AppOpsManager.OP_NONE, - getTemporaryAppAllowlistBroadcastOptions(REASON_LOCKED_BOOT_COMPLETED) - .toBundle(), true, - false, MY_PID, SYSTEM_UID, - Binder.getCallingUid(), Binder.getCallingPid(), userId); + // In case of headless system user mode, do not send boot complete broadcast for + // system user as it is sent by sendBootCompleted call. + if (!(UserManager.isHeadlessSystemUserMode() && uss.mHandle.isSystem())) { + // ACTION_LOCKED_BOOT_COMPLETED + sendLockedBootCompletedBroadcast(resultTo, userId); + } } } @@ -552,6 +545,21 @@ class UserController implements Handler.Callback { } } + private void sendLockedBootCompletedBroadcast(IIntentReceiver receiver, @UserIdInt int userId) { + final Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null); + intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT + | Intent.FLAG_RECEIVER_OFFLOAD + | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + mInjector.broadcastIntent(intent, null, receiver, 0, null, null, + new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, + AppOpsManager.OP_NONE, + getTemporaryAppAllowlistBroadcastOptions(REASON_LOCKED_BOOT_COMPLETED) + .toBundle(), true, + false, MY_PID, SYSTEM_UID, + Binder.getCallingUid(), Binder.getCallingPid(), userId); + } + /** * Step from {@link UserState#STATE_RUNNING_LOCKED} to * {@link UserState#STATE_RUNNING_UNLOCKING}. @@ -2167,26 +2175,22 @@ class UserController implements Handler.Callback { } void sendBootCompleted(IIntentReceiver resultTo) { - final boolean systemUserFinishedBooting; - // Get a copy of mStartedUsers to use outside of lock SparseArray<UserState> startedUsers; synchronized (mLock) { - systemUserFinishedBooting = mCurrentUserId != UserHandle.USER_SYSTEM; startedUsers = mStartedUsers.clone(); } for (int i = 0; i < startedUsers.size(); i++) { UserState uss = startedUsers.valueAt(i); - if (systemUserFinishedBooting && uss.mHandle.isSystem()) { - // On Automotive, at this point the system user has already been started and - // unlocked, and some of the tasks we do here have already been done. So skip those - // in that case. - // TODO(b/132262830): this workdound shouldn't be necessary once we move the - // headless-user start logic to UserManager-land - Slog.d(TAG, "sendBootCompleted(): skipping on non-current system user"); - continue; + if (!UserManager.isHeadlessSystemUserMode()) { + finishUserBoot(uss, resultTo); + } else if (uss.mHandle.isSystem()) { + // In case of headless system user mode, send only locked boot complete broadcast + // for system user since finishUserBoot call will be made using other code path; + // for non-system user, do nothing since finishUserBoot will be called elsewhere. + sendLockedBootCompletedBroadcast(resultTo, uss.mHandle.getIdentifier()); + return; } - finishUserBoot(uss, resultTo); } } diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java index 050b28b363d2..285f3185abc2 100644 --- a/services/core/java/com/android/server/biometrics/AuthService.java +++ b/services/core/java/com/android/server/biometrics/AuthService.java @@ -406,26 +406,49 @@ public class AuthService extends SystemService { mBiometricService.getCurrentModality( opPackageName, userId, callingUserId, authenticators); + final boolean isCredentialAllowed = Utils.isCredentialRequested(authenticators); + final String result; switch (getCredentialBackupModality(modality)) { case BiometricAuthenticator.TYPE_NONE: result = null; break; + case BiometricAuthenticator.TYPE_CREDENTIAL: result = getContext().getString( R.string.screen_lock_dialog_default_subtitle); break; + case BiometricAuthenticator.TYPE_FINGERPRINT: - result = getContext().getString( - R.string.fingerprint_dialog_default_subtitle); + if (isCredentialAllowed) { + result = getContext().getString( + R.string.fingerprint_or_screen_lock_dialog_default_subtitle); + } else { + result = getContext().getString( + R.string.fingerprint_dialog_default_subtitle); + } break; + case BiometricAuthenticator.TYPE_FACE: - result = getContext().getString(R.string.face_dialog_default_subtitle); + if (isCredentialAllowed) { + result = getContext().getString( + R.string.face_or_screen_lock_dialog_default_subtitle); + } else { + result = getContext().getString(R.string.face_dialog_default_subtitle); + } break; + default: - result = getContext().getString(R.string.biometric_dialog_default_subtitle); + if (isCredentialAllowed) { + result = getContext().getString( + R.string.biometric_or_screen_lock_dialog_default_subtitle); + } else { + result = getContext().getString( + R.string.biometric_dialog_default_subtitle); + } break; } + return result; } finally { Binder.restoreCallingIdentity(identity); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java index b4c9b290cd06..4ca85d000d19 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java @@ -139,8 +139,4 @@ public class TestHal extends IFace.Stub { } }; } - - @Override - public void reset() { - } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java index 8547a689dfb1..0b7f3abc9005 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java @@ -140,9 +140,5 @@ public class TestHal extends IFingerprint.Stub { } }; } - - @Override - public void reset() { - } } diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 5020917f8eb1..6712c5474921 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -57,6 +57,7 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.view.autofill.AutofillManagerInternal; import android.widget.Toast; @@ -274,6 +275,9 @@ public class ClipboardService extends SystemService { /** Package of the app that set {@link #primaryClip}. */ String mPrimaryClipPackage; + /** Uids that have already triggered a toast notification for {@link #primaryClip} */ + final SparseBooleanArray mNotifiedUids = new SparseBooleanArray(); + final HashSet<String> activePermissionOwners = new HashSet<String>(); @@ -649,6 +653,7 @@ public class ClipboardService extends SystemService { return; } clipboard.primaryClip = clip; + clipboard.mNotifiedUids.clear(); if (clip != null) { clipboard.primaryClipUid = uid; clipboard.mPrimaryClipPackage = sourcePackage; @@ -939,35 +944,42 @@ public class ClipboardService extends SystemService { && mAutofillInternal.isAugmentedAutofillServiceForUser(uid, userId)) { return; } + // Don't notify if already notified for this uid and clip. + if (clipboard.mNotifiedUids.get(uid)) { + return; + } + clipboard.mNotifiedUids.put(uid, true); - // Retrieve the app label of the source of the clip data - CharSequence sourceAppLabel = null; - if (clipboard.mPrimaryClipPackage != null) { - try { - sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser( - clipboard.mPrimaryClipPackage, 0, userId)); - } catch (PackageManager.NameNotFoundException e) { - // leave label as null + Binder.withCleanCallingIdentity(() -> { + // Retrieve the app label of the source of the clip data + CharSequence sourceAppLabel = null; + if (clipboard.mPrimaryClipPackage != null) { + try { + sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser( + clipboard.mPrimaryClipPackage, 0, userId)); + } catch (PackageManager.NameNotFoundException e) { + // leave label as null + } } - } - try { - CharSequence callingAppLabel = mPm.getApplicationLabel( - mPm.getApplicationInfoAsUser(callingPackage, 0, userId)); - String message; - if (sourceAppLabel != null) { - message = getContext().getString( - R.string.pasted_from_app, callingAppLabel, sourceAppLabel); - } else { - message = getContext().getString(R.string.pasted_from_clipboard, callingAppLabel); + try { + CharSequence callingAppLabel = mPm.getApplicationLabel( + mPm.getApplicationInfoAsUser(callingPackage, 0, userId)); + String message; + if (sourceAppLabel != null) { + message = getContext().getString( + R.string.pasted_from_app, callingAppLabel, sourceAppLabel); + } else { + message = getContext().getString( + R.string.pasted_from_clipboard, callingAppLabel); + } + Slog.i(TAG, message); + Toast.makeText( + getContext(), UiThread.get().getLooper(), message, Toast.LENGTH_SHORT) + .show(); + } catch (PackageManager.NameNotFoundException e) { + // do nothing } - Slog.i(TAG, message); - Binder.withCleanCallingIdentity(() -> - Toast.makeText(getContext(), UiThread.get().getLooper(), message, - Toast.LENGTH_SHORT) - .show()); - } catch (PackageManager.NameNotFoundException e) { - // do nothing - } + }); } } diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java index 5cf478a3ef1f..ae9b0015de43 100644 --- a/services/core/java/com/android/server/compat/CompatChange.java +++ b/services/core/java/com/android/server/compat/CompatChange.java @@ -28,6 +28,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import com.android.internal.compat.AndroidBuildClassifier; import com.android.internal.compat.CompatibilityChangeInfo; import com.android.internal.compat.OverrideAllowedState; import com.android.server.compat.config.Change; @@ -55,7 +56,7 @@ public final class CompatChange extends CompatibilityChangeInfo { * A change ID to be used only in the CTS test for this SystemApi */ @ChangeId - @EnabledSince(targetSdkVersion = 1235) // Needs to be > test APK targetSdkVersion. + @EnabledSince(targetSdkVersion = 31) // Needs to be > test APK targetSdkVersion. static final long CTS_SYSTEM_API_CHANGEID = 149391281; // This is a bug id. /** @@ -233,7 +234,7 @@ public final class CompatChange extends CompatibilityChangeInfo { * @param app Info about the app in question * @return {@code true} if the change should be enabled for the package. */ - boolean isEnabled(ApplicationInfo app) { + boolean isEnabled(ApplicationInfo app, AndroidBuildClassifier buildClassifier) { if (app == null) { return defaultValue(); } @@ -244,7 +245,13 @@ public final class CompatChange extends CompatibilityChangeInfo { return false; } if (getEnableSinceTargetSdk() != -1) { - return app.targetSdkVersion >= getEnableSinceTargetSdk(); + // If the change is gated by a platform version newer than the one currently installed + // on the device, disregard the app's target sdk version. + int compareSdk = Math.min(app.targetSdkVersion, buildClassifier.platformTargetSdk()); + if (compareSdk != app.targetSdkVersion) { + compareSdk = app.targetSdkVersion; + } + return compareSdk >= getEnableSinceTargetSdk(); } return true; } diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index 2c053b421904..ef86f42d6c3c 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -74,12 +74,14 @@ final class CompatConfig { private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>(); private final OverrideValidatorImpl mOverrideValidator; + private final AndroidBuildClassifier mAndroidBuildClassifier; private Context mContext; private File mOverridesFile; @VisibleForTesting CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) { mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this); + mAndroidBuildClassifier = androidBuildClassifier; mContext = context; } @@ -133,7 +135,7 @@ final class CompatConfig { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { CompatChange c = mChanges.valueAt(i); - if (!c.isEnabled(app)) { + if (!c.isEnabled(app, mAndroidBuildClassifier)) { disabled.add(c.getId()); } } @@ -175,7 +177,7 @@ final class CompatConfig { // we know nothing about this change: default behaviour is enabled. return true; } - return c.isEnabled(app); + return c.isEnabled(app, mAndroidBuildClassifier); } } @@ -475,7 +477,7 @@ final class CompatConfig { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { CompatChange c = mChanges.valueAt(i); - if (c.isEnabled(applicationInfo)) { + if (c.isEnabled(applicationInfo, mAndroidBuildClassifier)) { enabled.add(c.getId()); } else { disabled.add(c.getId()); diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java index fe5b4a98797d..aa66a1a8b01f 100644 --- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java +++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java @@ -22,6 +22,7 @@ import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARG import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE; import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH; import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE; +import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -85,6 +86,9 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub { if (debuggableBuild) { return new OverrideAllowedState(ALLOWED, -1, -1); } + if (maxTargetSdk >= mAndroidBuildClassifier.platformTargetSdk()) { + return new OverrideAllowedState(PLATFORM_TOO_OLD, -1, maxTargetSdk); + } PackageManager packageManager = mContext.getPackageManager(); if (packageManager == null) { throw new IllegalStateException("No PackageManager!"); diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index d17753fe81bd..2be39aa24294 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -66,18 +66,22 @@ public class PlatformCompat extends IPlatformCompat.Stub { private final Context mContext; private final ChangeReporter mChangeReporter; private final CompatConfig mCompatConfig; + private final AndroidBuildClassifier mBuildClassifier; public PlatformCompat(Context context) { mContext = context; mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER); - mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext); + mBuildClassifier = new AndroidBuildClassifier(); + mCompatConfig = CompatConfig.create(mBuildClassifier, mContext); } @VisibleForTesting - PlatformCompat(Context context, CompatConfig compatConfig) { + PlatformCompat(Context context, CompatConfig compatConfig, + AndroidBuildClassifier buildClassifier) { mContext = context; mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER); mCompatConfig = compatConfig; + mBuildClassifier = buildClassifier; registerPackageReceiver(context); } @@ -392,7 +396,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { return false; } if (change.getEnableSinceTargetSdk() > 0) { - return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q; + return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q + && change.getEnableSinceTargetSdk() <= mBuildClassifier.platformTargetSdk(); } return true; } diff --git a/services/core/java/com/android/server/connectivity/ConnectivityResources.java b/services/core/java/com/android/server/connectivity/ConnectivityResources.java new file mode 100644 index 000000000000..45cf21e035ca --- /dev/null +++ b/services/core/java/com/android/server/connectivity/ConnectivityResources.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity; + +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.util.Log; + +import com.android.server.ConnectivityService; + +import java.util.List; + +/** + * Utility to obtain the {@link ConnectivityService} {@link Resources}, in the + * ServiceConnectivityResources APK. + */ +public class ConnectivityResources { + private static final String RESOURCES_APK_INTENT = + "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK"; + private static final String RES_PKG_DIR = "/apex/com.android.tethering/"; + + @NonNull + private final Context mContext; + + @Nullable + private Resources mResources = null; + + public ConnectivityResources(Context context) { + mContext = context; + } + + /** + * Get the {@link Resources} of the ServiceConnectivityResources APK. + */ + public synchronized Resources get() { + if (mResources != null) { + return mResources; + } + + final List<ResolveInfo> pkgs = mContext.getPackageManager() + .queryIntentActivities(new Intent(RESOURCES_APK_INTENT), MATCH_SYSTEM_ONLY); + pkgs.removeIf(pkg -> !pkg.activityInfo.applicationInfo.sourceDir.startsWith(RES_PKG_DIR)); + if (pkgs.size() > 1) { + Log.wtf(ConnectivityResources.class.getSimpleName(), + "More than one package found: " + pkgs); + } + if (pkgs.isEmpty()) { + throw new IllegalStateException("No connectivity resource package found"); + } + + final Context pkgContext; + try { + pkgContext = mContext.createPackageContext( + pkgs.get(0).activityInfo.applicationInfo.packageName, 0 /* flags */); + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalStateException("Resolved package not found", e); + } + + mResources = pkgContext.getResources(); + return mResources; + } +} diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index fa80b25f9026..c66a280f2b02 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -16,6 +16,8 @@ package com.android.server.connectivity; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; + import static com.android.net.module.util.CollectionUtils.contains; import android.annotation.NonNull; @@ -35,6 +37,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.NetworkStackConstants; +import com.android.server.ConnectivityService; import java.net.Inet6Address; import java.util.Objects; @@ -94,12 +97,15 @@ public class Nat464Xlat { private Inet6Address mIPv6Address; private State mState = State.IDLE; + private boolean mEnableClatOnCellular; private boolean mPrefixDiscoveryRunning; - public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver) { + public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver, + ConnectivityService.Dependencies deps) { mDnsResolver = dnsResolver; mNetd = netd; mNetwork = nai; + mEnableClatOnCellular = deps.getCellular464XlatEnabled(); } /** @@ -111,7 +117,7 @@ public class Nat464Xlat { * @return true if the network requires clat, false otherwise. */ @VisibleForTesting - protected static boolean requiresClat(NetworkAgentInfo nai) { + protected boolean requiresClat(NetworkAgentInfo nai) { // TODO: migrate to NetworkCapabilities.TRANSPORT_*. final boolean supported = contains(NETWORK_TYPES, nai.networkInfo.getType()); final boolean connected = contains(NETWORK_STATES, nai.networkInfo.getState()); @@ -126,7 +132,9 @@ public class Nat464Xlat { final boolean skip464xlat = (nai.netAgentConfig() != null) && nai.netAgentConfig().skip464xlat; - return supported && connected && isIpv6OnlyNetwork && !skip464xlat; + return supported && connected && isIpv6OnlyNetwork && !skip464xlat + && (nai.networkCapabilities.hasTransport(TRANSPORT_CELLULAR) + ? isCellular464XlatEnabled() : true); } /** @@ -137,7 +145,7 @@ public class Nat464Xlat { * @return true if the network should start clat, false otherwise. */ @VisibleForTesting - protected static boolean shouldStartClat(NetworkAgentInfo nai) { + protected boolean shouldStartClat(NetworkAgentInfo nai) { LinkProperties lp = nai.linkProperties; return requiresClat(nai) && lp != null && lp.getNat64Prefix() != null; } @@ -507,4 +515,9 @@ public class Nat464Xlat { protected int getNetId() { return mNetwork.network.getNetId(); } + + @VisibleForTesting + protected boolean isCellular464XlatEnabled() { + return mEnableClatOnCellular; + } } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 1d0e11569c80..803cc9d31c35 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -341,7 +341,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, int score, Context context, Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd, IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid, - QosCallbackTracker qosCallbackTracker) { + QosCallbackTracker qosCallbackTracker, ConnectivityService.Dependencies deps) { Objects.requireNonNull(net); Objects.requireNonNull(info); Objects.requireNonNull(lp); @@ -355,7 +355,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { linkProperties = lp; networkCapabilities = nc; mScore = score; - clatd = new Nat464Xlat(this, netd, dnsResolver); + clatd = new Nat464Xlat(this, netd, dnsResolver, deps); mConnService = connService; mContext = context; mHandler = handler; diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index 9411e33434d8..488677ac1b59 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -31,14 +31,17 @@ import static android.os.Process.SYSTEM_UID; import static com.android.net.module.util.CollectionUtils.toIntArray; import android.annotation.NonNull; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PackageManagerInternal; import android.net.INetd; import android.net.UidRange; +import android.net.Uri; import android.os.Build; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -54,7 +57,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.net.module.util.CollectionUtils; -import com.android.server.LocalServices; import java.util.ArrayList; import java.util.HashMap; @@ -71,7 +73,7 @@ import java.util.Set; * * @hide */ -public class PermissionMonitor implements PackageManagerInternal.PackageListObserver { +public class PermissionMonitor { private static final String TAG = "PermissionMonitor"; private static final boolean DBG = true; protected static final Boolean SYSTEM = Boolean.TRUE; @@ -83,6 +85,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse private final SystemConfigManager mSystemConfigManager; private final INetd mNetd; private final Dependencies mDeps; + private final Context mContext; @GuardedBy("this") private final Set<UserHandle> mUsers = new HashSet<>(); @@ -102,6 +105,25 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse @GuardedBy("this") private final Set<Integer> mAllApps = new HashSet<>(); + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); + final Uri packageData = intent.getData(); + final String packageName = + packageData != null ? packageData.getSchemeSpecificPart() : null; + + if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { + onPackageAdded(packageName, uid); + } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + onPackageRemoved(packageName, uid); + } else { + Log.wtf(TAG, "received unexpected intent: " + action); + } + } + }; + /** * Dependencies of PermissionMonitor, for injection in tests. */ @@ -127,6 +149,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse mSystemConfigManager = context.getSystemService(SystemConfigManager.class); mNetd = netd; mDeps = deps; + mContext = context; } // Intended to be called only once at startup, after the system is ready. Installs a broadcast @@ -134,12 +157,14 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse public synchronized void startMonitoring() { log("Monitoring"); - PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); - if (pmi != null) { - pmi.getPackageList(this); - } else { - loge("failed to get the PackageManagerInternal service"); - } + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); + intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + intentFilter.addDataScheme("package"); + mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */).registerReceiver( + mIntentReceiver, intentFilter, null /* broadcastPermission */, + null /* scheduler */); + List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS | MATCH_ANY_USER); if (apps == null) { @@ -347,9 +372,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse * * @hide */ - @Override public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) { - sendPackagePermissionsForUid(uid, getPermissionForUid(uid)); + // TODO: Netd is using appId for checking traffic permission. Correct the methods that are + // using appId instead of uid actually + sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid)); // If multiple packages share a UID (cf: android:sharedUserId) and ask for different // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is). @@ -384,9 +410,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse * * @hide */ - @Override public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) { - sendPackagePermissionsForUid(uid, getPermissionForUid(uid)); + // TODO: Netd is using appId for checking traffic permission. Correct the methods that are + // using appId instead of uid actually + sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid)); // If the newly-removed package falls within some VPN's uid range, update Netd with it. // This needs to happen before the mApps update below, since removeBypassingUids() depends @@ -432,19 +459,6 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse } } - /** - * Called when a package is changed. - * - * @param packageName The name of the changed package. - * @param uid The uid of the changed package. - * - * @hide - */ - @Override - public synchronized void onPackageChanged(@NonNull final String packageName, final int uid) { - sendPackagePermissionsForUid(uid, getPermissionForUid(uid)); - } - private static int getNetdPermissionMask(String[] requestedPermissions, int[] requestedPermissionsFlags) { int permissions = 0; diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 027b9afba392..0e714969a69b 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -791,12 +791,13 @@ public final class ContentService extends IContentService.Stub { public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) { enforceCrossUserPermission(userId, "no permission to read sync settings for user " + userId); + final int callingUid = Binder.getCallingUid(); // This makes it so that future permission checks will be in the context of this // process rather than the caller's process. We will restore this before returning. final long identityToken = clearCallingIdentity(); try { SyncManager syncManager = getSyncManager(); - return syncManager.getSyncAdapterTypes(userId); + return syncManager.getSyncAdapterTypes(callingUid, userId); } finally { restoreCallingIdentity(identityToken); } diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index df870125e253..ac7e01ed4d72 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -89,6 +89,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; import android.provider.Settings; +import android.text.TextUtils; import android.text.format.TimeMigrationUtils; import android.util.EventLog; import android.util.Log; @@ -1257,16 +1258,19 @@ public class SyncManager { syncExemptionFlag, callingUid, callingPid, callingPackage); } - public SyncAdapterType[] getSyncAdapterTypes(int userId) { + public SyncAdapterType[] getSyncAdapterTypes(int callingUid, int userId) { final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos; serviceInfos = mSyncAdapters.getAllServices(userId); - SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()]; - int i = 0; + final List<SyncAdapterType> types = new ArrayList<>(serviceInfos.size()); for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) { - types[i] = serviceInfo.type; - ++i; + final String packageName = serviceInfo.type.getPackageName(); + if (!TextUtils.isEmpty(packageName) && mPackageManagerInternal.filterAppAccess( + packageName, callingUid, userId)) { + continue; + } + types.add(serviceInfo.type); } - return types; + return types.toArray(new SyncAdapterType[] {}); } public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) { diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 174d4b2fe00d..96a74161a6eb 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1128,7 +1128,7 @@ public final class DisplayManagerService extends SystemService { recordTopInsetLocked(display); } addDisplayPowerControllerLocked(display); - mDisplayStates.append(displayId, Display.STATE_OFF); + mDisplayStates.append(displayId, Display.STATE_UNKNOWN); mDisplayBrightnesses.append(displayId, display.getDisplayInfoLocked().brightnessDefault); DisplayManagerGlobal.invalidateLocalDisplayInfoCaches(); @@ -1204,16 +1204,15 @@ public final class DisplayManagerService extends SystemService { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); - final int state; final int displayId = display.getDisplayIdLocked(); + final int state = mDisplayStates.get(displayId); - if (display.isEnabled()) { - state = mDisplayStates.get(displayId); - } else { - state = Display.STATE_OFF; + // Only send a request for display state if the display state has already been + // initialized by DisplayPowercontroller. + if (state != Display.STATE_UNKNOWN) { + final float brightness = mDisplayBrightnesses.get(displayId); + return device.requestDisplayStateLocked(state, brightness); } - final float brightness = mDisplayBrightnesses.get(displayId); - return device.requestDisplayStateLocked(state, brightness); } return null; } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 011732682ace..7b107b857a79 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -982,7 +982,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mWaitingForNegativeProximity = false; mIgnoreProximityUntilChanged = false; } - if (mScreenOffBecauseOfProximity) { + + if (!mLogicalDisplay.isEnabled() || mScreenOffBecauseOfProximity) { state = Display.STATE_OFF; } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index d88896c01e4b..aaec89afa94c 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -682,7 +682,10 @@ final class LocalDisplayAdapter extends DisplayAdapter { || oldState == Display.STATE_ON_SUSPEND) { setDisplayState(Display.STATE_ON); currentState = Display.STATE_ON; - } else { + + // If UNKNOWN, we still want to set the initial display state, + // otherwise, return early. + } else if (oldState != Display.STATE_UNKNOWN) { return; // old state and new state is off } } diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index d6826be248df..fcfa674dcc4e 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -357,7 +357,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { for (int i = mDisplayGroups.size() - 1; i >= 0; i--) { final int groupId = mDisplayGroups.keyAt(i); final DisplayGroup group = mDisplayGroups.valueAt(i); - final boolean wasPreviouslyUpdated = mUpdatedDisplayGroups.indexOfKey(groupId) < 0; + final boolean wasPreviouslyUpdated = mUpdatedDisplayGroups.indexOfKey(groupId) > -1; final int changeCount = group.getChangeCountLocked(); if (group.isEmptyLocked()) { diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java index d2baaf2228a1..0ba191c0762f 100644 --- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java @@ -91,6 +91,10 @@ final class WifiDisplayAdapter extends DisplayAdapter { private boolean mPendingStatusChangeBroadcast; + private static final String[] RECEIVER_PERMISSIONS_FOR_BROADCAST = { + android.Manifest.permission.ACCESS_FINE_LOCATION, + }; + // Called with SyncRoot lock held. public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, @@ -432,7 +436,8 @@ final class WifiDisplayAdapter extends DisplayAdapter { } // Send protected broadcast about wifi display status to registered receivers. - getContext().sendBroadcastAsUser(intent, UserHandle.ALL); + getContext().createContextAsUser(UserHandle.ALL, 0) + .sendBroadcastWithMultiplePermissions(intent, RECEIVER_PERMISSIONS_FOR_BROADCAST); } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java index 900ec905609f..2b7d2074a7e0 100644 --- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java +++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java @@ -31,17 +31,18 @@ import android.os.SharedMemory; import android.os.ShellCallback; import android.system.ErrnoException; import android.text.FontConfig; +import android.text.TextUtils; import android.util.AndroidException; import android.util.IndentingPrintWriter; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.graphics.fonts.IFontManager; +import com.android.internal.security.VerityUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.SystemService; -import com.android.server.security.VerityUtils; import java.io.File; import java.io.FileDescriptor; @@ -66,6 +67,8 @@ public final class FontManagerService extends IFontManager.Stub { @Override public FontConfig getFontConfig() { + getContext().enforceCallingPermission(Manifest.permission.UPDATE_FONTS, + "UPDATE_FONTS permission required."); return getSystemFontConfig(); } @@ -148,10 +151,24 @@ public final class FontManagerService extends IFontManager.Stub { /* package */ static class OtfFontFileParser implements UpdatableFontDir.FontFileParser { @Override - public String getPostScriptName(File file) throws IOException { + public String getCanonicalFileName(File file) throws IOException { ByteBuffer buffer = mmap(file); try { - return FontFileUtil.getPostScriptName(buffer, 0); + String psName = FontFileUtil.getPostScriptName(buffer, 0); + int isType1Font = FontFileUtil.isPostScriptType1Font(buffer, 0); + int isCollection = FontFileUtil.isCollectionFont(buffer); + + if (TextUtils.isEmpty(psName) || isType1Font == -1 || isCollection == -1) { + return null; + } + + String extension; + if (isCollection == 1) { + extension = isType1Font == 1 ? ".otc" : ".ttc"; + } else { + extension = isType1Font == 1 ? ".otf" : ".ttf"; + } + return psName + extension; } finally { NioUtils.freeDirectBuffer(buffer); } diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java index 86dbe86f85ee..4f95d27a085e 100644 --- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java +++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java @@ -56,14 +56,12 @@ final class UpdatableFontDir { private static final String TAG = "UpdatableFontDir"; private static final String RANDOM_DIR_PREFIX = "~~"; - // TODO: Support .otf - private static final String ALLOWED_EXTENSION = ".ttf"; private static final String CONFIG_XML_FILE = "/data/fonts/config/config.xml"; /** Interface to mock font file access in tests. */ interface FontFileParser { - String getPostScriptName(File file) throws IOException; + String getCanonicalFileName(File file) throws IOException; long getRevision(File file) throws IOException; } @@ -321,20 +319,20 @@ final class UpdatableFontDir { FontManager.RESULT_ERROR_VERIFICATION_FAILURE, "Failed to setup fs-verity.", e); } - String postScriptName; + String canonicalFileName; try { - postScriptName = mParser.getPostScriptName(tempNewFontFile); + canonicalFileName = mParser.getCanonicalFileName(tempNewFontFile); } catch (IOException e) { throw new SystemFontException( FontManager.RESULT_ERROR_INVALID_FONT_FILE, "Failed to read PostScript name from font file", e); } - if (postScriptName == null) { + if (canonicalFileName == null) { throw new SystemFontException( FontManager.RESULT_ERROR_INVALID_FONT_NAME, "Failed to read PostScript name from font file"); } - File newFontFile = new File(newDir, postScriptName + ALLOWED_EXTENSION); + File newFontFile = new File(newDir, canonicalFileName); if (!mFsverityUtil.rename(tempNewFontFile, newFontFile)) { throw new SystemFontException( FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE, @@ -380,20 +378,38 @@ final class UpdatableFontDir { return dir; } + private FontFileInfo lookupFontFileInfo(File file) { + String name = file.getName(); + + if (!name.endsWith(".ttf") && !name.endsWith(".otf") && !name.endsWith(".ttc") + && !name.endsWith(".otc")) { + return null; + } + String key = name.substring(0, name.length() - 4); + return mFontFileInfoMap.get(key); + } + + private void putFontFileInfo(FontFileInfo info) { + String name = info.getFile().getName(); + // The file name in FontFileInfo is already validated. Thus, just strip last 4 chars. + String key = name.substring(0, name.length() - 4); + mFontFileInfoMap.put(key, info); + } + /** * Add the given {@link FontFileInfo} to {@link #mFontFileInfoMap} if its font revision is * higher than the currently used font file (either in {@link #mFontFileInfoMap} or {@link * #mPreinstalledFontDirs}). */ private boolean addFileToMapIfNewer(FontFileInfo fontFileInfo, boolean deleteOldFile) { - String name = fontFileInfo.getFile().getName(); - FontFileInfo existingInfo = mFontFileInfoMap.get(name); + FontFileInfo existingInfo = lookupFontFileInfo(fontFileInfo.getFile()); final boolean shouldAddToMap; if (existingInfo == null) { // We got a new updatable font. We need to check if it's newer than preinstalled fonts. // Note that getPreinstalledFontRevision() returns -1 if there is no preinstalled font // with 'name'. - shouldAddToMap = getPreinstalledFontRevision(name) < fontFileInfo.getRevision(); + long preInstalledRev = getPreinstalledFontRevision(fontFileInfo.getFile().getName()); + shouldAddToMap = preInstalledRev < fontFileInfo.getRevision(); } else { shouldAddToMap = existingInfo.getRevision() < fontFileInfo.getRevision(); } @@ -401,7 +417,7 @@ final class UpdatableFontDir { if (deleteOldFile && existingInfo != null) { FileUtils.deleteContentsAndDir(existingInfo.getRandomizedFontDir()); } - mFontFileInfoMap.put(name, fontFileInfo); + putFontFileInfo(fontFileInfo); } else { if (deleteOldFile) { FileUtils.deleteContentsAndDir(fontFileInfo.getRandomizedFontDir()); @@ -464,15 +480,18 @@ final class UpdatableFontDir { */ private boolean validateFontFileName(File file) { String fileName = file.getName(); - String postScriptName = getPostScriptName(file); - return (postScriptName + ALLOWED_EXTENSION).equals(fileName); + String canonicalFileName = getCanonicalFileName(file); + if (canonicalFileName == null) { + return false; + } + return canonicalFileName.equals(fileName); } /** Returns the PostScript name of the given font file, or null. */ @Nullable - private String getPostScriptName(File file) { + private String getCanonicalFileName(File file) { try { - return mParser.getPostScriptName(file); + return mParser.getCanonicalFileName(file); } catch (IOException e) { Slog.e(TAG, "Failed to read font file", e); return null; @@ -514,7 +533,7 @@ final class UpdatableFontDir { List<FontConfig.Font> fontList = fontFamily.getFontList(); for (int i = 0; i < fontList.size(); i++) { FontConfig.Font font = fontList.get(i); - FontFileInfo info = mFontFileInfoMap.get(font.getFile().getName()); + FontFileInfo info = lookupFontFileInfo(font.getFile()); if (info == null) { return null; } @@ -537,8 +556,9 @@ final class UpdatableFontDir { Map<String, File> getFontFileMap() { Map<String, File> map = new ArrayMap<>(); - for (Map.Entry<String, FontFileInfo> entry : mFontFileInfoMap.entrySet()) { - map.put(entry.getKey(), entry.getValue().getFile()); + for (int i = 0; i < mFontFileInfoMap.size(); ++i) { + File file = mFontFileInfoMap.valueAt(i).getFile(); + map.put(file.getName(), file); } return map; } diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java index c23e2e691b55..947ee24f8e02 100644 --- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java @@ -97,11 +97,16 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { @Override public boolean start() { - // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0. - // The message is re-sent at the end of the action for devices that don't support 2.0. - sendSetStreamPath(); - int targetPowerStatus = localDevice().mService.getHdmiCecNetwork() - .getCecDeviceInfo(getTargetAddress()).getDevicePowerStatus(); + // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0. + // The message is re-sent at the end of the action for devices that don't support 2.0. + sendSetStreamPath(); + int targetPowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN; + HdmiDeviceInfo targetDevice = localDevice().mService.getHdmiCecNetwork().getCecDeviceInfo( + getTargetAddress()); + if (targetDevice != null) { + targetPowerStatus = targetDevice.getDevicePowerStatus(); + } + if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) { queryDevicePowerStatus(); } else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java index 624af30854dc..6fbb26c4a5ee 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java @@ -35,33 +35,19 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings.Global; import android.util.ArrayMap; -import android.util.Slog; +import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ConcurrentUtils; -import com.android.server.hdmi.cec.config.CecSettings; -import com.android.server.hdmi.cec.config.Setting; -import com.android.server.hdmi.cec.config.Value; -import com.android.server.hdmi.cec.config.XmlParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; -import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map.Entry; -import java.util.Set; import java.util.concurrent.Executor; -import javax.xml.datatype.DatatypeConfigurationException; - /** * The {@link HdmiCecConfig} class is used for getting information about * available HDMI CEC settings. @@ -74,6 +60,10 @@ public class HdmiCecConfig { private static final String SHARED_PREFS_DIR = "shared_prefs"; private static final String SHARED_PREFS_NAME = "cec_config.xml"; + private static final int STORAGE_SYSPROPS = 0; + private static final int STORAGE_GLOBAL_SETTINGS = 1; + private static final int STORAGE_SHARED_PREFS = 2; + @IntDef({ STORAGE_SYSPROPS, STORAGE_GLOBAL_SETTINGS, @@ -81,10 +71,6 @@ public class HdmiCecConfig { }) private @interface Storage {} - private static final int STORAGE_SYSPROPS = 0; - private static final int STORAGE_GLOBAL_SETTINGS = 1; - private static final int STORAGE_SHARED_PREFS = 2; - private static final String VALUE_TYPE_STRING = "string"; private static final String VALUE_TYPE_INT = "int"; @@ -96,8 +82,6 @@ public class HdmiCecConfig { @NonNull private final Context mContext; @NonNull private final StorageAdapter mStorageAdapter; - @Nullable private final CecSettings mSystemConfig; - @Nullable private final CecSettings mVendorOverride; private final Object mLock = new Object(); @@ -107,6 +91,18 @@ public class HdmiCecConfig { private SettingsObserver mSettingsObserver; + private LinkedHashMap<String, Setting> mSettings = new LinkedHashMap<>(); + + /** + * Exception thrown when the CEC Configuration setup verification fails. + * This usually means a settings lacks default value or storage/storage key. + */ + public static class VerificationException extends RuntimeException { + public VerificationException(String message) { + super(message); + } + } + /** * Listener used to get notifications when value of a setting changes. */ @@ -202,91 +198,297 @@ public class HdmiCecConfig { } } - @VisibleForTesting - HdmiCecConfig(@NonNull Context context, - @NonNull StorageAdapter storageAdapter, - @Nullable CecSettings systemConfig, - @Nullable CecSettings vendorOverride) { - mContext = context; - mStorageAdapter = storageAdapter; - mSystemConfig = systemConfig; - mVendorOverride = vendorOverride; - if (mSystemConfig == null) { - Slog.i(TAG, "CEC system configuration XML missing."); + private class Value { + private final String mStringValue; + private final Integer mIntValue; + + Value(@NonNull String value) { + mStringValue = value; + mIntValue = null; } - if (mVendorOverride == null) { - Slog.i(TAG, "CEC OEM configuration override XML missing."); + + Value(@NonNull Integer value) { + mStringValue = null; + mIntValue = value; } - } - HdmiCecConfig(@NonNull Context context) { - this(context, new StorageAdapter(context), - readSettingsFromFile(Environment.buildPath(Environment.getRootDirectory(), - ETC_DIR, CONFIG_FILE)), - readSettingsFromFile(Environment.buildPath(Environment.getVendorDirectory(), - ETC_DIR, CONFIG_FILE))); + String getStringValue() { + return mStringValue; + } + + Integer getIntValue() { + return mIntValue; + } } - @Nullable - private static CecSettings readSettingsFromFile(@NonNull File file) { - if (!file.exists()) { - return null; + private class Setting { + @NonNull private final Context mContext; + @NonNull private final @CecSettingName String mName; + private final boolean mUserConfigurable; + + private Value mDefaultValue = null; + private List<Value> mAllowedValues = new ArrayList<>(); + + Setting(@NonNull Context context, + @NonNull @CecSettingName String name, + int userConfResId) { + mContext = context; + mName = name; + mUserConfigurable = mContext.getResources().getBoolean(userConfResId); } - if (!file.isFile()) { - Slog.e(TAG, "CEC configuration is not a file: " + file + ", skipping."); - return null; + + public @CecSettingName String getName() { + return mName; } - try (InputStream in = new BufferedInputStream(new FileInputStream(file))) { - return XmlParser.read(in); - } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) { - Slog.e(TAG, "Encountered an error while reading/parsing CEC config file: " + file, e); + + public @ValueType String getValueType() { + return getDefaultValue().getStringValue() != null + ? VALUE_TYPE_STRING + : VALUE_TYPE_INT; } - return null; - } - @NonNull - @VisibleForTesting - static HdmiCecConfig createFromStrings(@NonNull Context context, - @NonNull StorageAdapter storageAdapter, - @Nullable String productConfigXml, - @Nullable String vendorOverrideXml) { - CecSettings productConfig = null; - CecSettings vendorOverride = null; - try { - if (productConfigXml != null) { - productConfig = XmlParser.read( - new ByteArrayInputStream(productConfigXml.getBytes())); - } - if (vendorOverrideXml != null) { - vendorOverride = XmlParser.read( - new ByteArrayInputStream(vendorOverrideXml.getBytes())); + public Value getDefaultValue() { + if (mDefaultValue == null) { + throw new VerificationException("Invalid CEC setup for '" + + this.getName() + "' setting. " + + "Setting has no default value."); } - } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) { - Slog.e(TAG, "Encountered an error while reading/parsing CEC config strings", e); + return mDefaultValue; } - return new HdmiCecConfig(context, storageAdapter, productConfig, vendorOverride); - } - @Nullable - private Setting getSetting(@NonNull String name) { - if (mSystemConfig == null) { - return null; - } - if (mVendorOverride != null) { - // First read from the vendor override. - for (Setting setting : mVendorOverride.getSetting()) { - if (setting.getName().equals(name)) { - return setting; + public boolean getUserConfigurable() { + return mUserConfigurable; + } + + private void registerValue(@NonNull Value value, + int allowedResId, int defaultResId) { + if (mContext.getResources().getBoolean(allowedResId)) { + mAllowedValues.add(value); + if (mContext.getResources().getBoolean(defaultResId)) { + if (mDefaultValue != null) { + throw new VerificationException("Invalid CEC setup for '" + + this.getName() + "' setting. " + + "Setting already has a default value."); + } + mDefaultValue = value; } } } - // If not found, try the system config. - for (Setting setting : mSystemConfig.getSetting()) { - if (setting.getName().equals(name)) { - return setting; - } + + public void registerValue(@NonNull String value, int allowedResId, + int defaultResId) { + registerValue(new Value(value), allowedResId, defaultResId); } - return null; + + public void registerValue(int value, int allowedResId, + int defaultResId) { + registerValue(new Value(value), allowedResId, defaultResId); + } + + + public List<Value> getAllowedValues() { + return mAllowedValues; + } + } + + @VisibleForTesting + HdmiCecConfig(@NonNull Context context, + @NonNull StorageAdapter storageAdapter) { + mContext = context; + mStorageAdapter = storageAdapter; + + Setting hdmiCecEnabled = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + R.bool.config_cecHdmiCecEnabled_userConfigurable); + hdmiCecEnabled.registerValue(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED, + R.bool.config_cecHdmiCecControlEnabled_allowed, + R.bool.config_cecHdmiCecControlEnabled_default); + hdmiCecEnabled.registerValue(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED, + R.bool.config_cecHdmiCecControlDisabled_allowed, + R.bool.config_cecHdmiCecControlDisabled_default); + + Setting hdmiCecVersion = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, + R.bool.config_cecHdmiCecVersion_userConfigurable); + hdmiCecVersion.registerValue(HdmiControlManager.HDMI_CEC_VERSION_1_4_B, + R.bool.config_cecHdmiCecVersion14b_allowed, + R.bool.config_cecHdmiCecVersion14b_default); + hdmiCecVersion.registerValue(HdmiControlManager.HDMI_CEC_VERSION_2_0, + R.bool.config_cecHdmiCecVersion20_allowed, + R.bool.config_cecHdmiCecVersion20_default); + + Setting powerControlMode = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE, + R.bool.config_cecSendStandbyOnSleep_userConfigurable); + powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_TV, + R.bool.config_cecPowerControlModeTv_allowed, + R.bool.config_cecPowerControlModeTv_default); + powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST, + R.bool.config_cecPowerControlModeBroadcast_allowed, + R.bool.config_cecPowerControlModeBroadcast_default); + powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_NONE, + R.bool.config_cecPowerControlModeNone_allowed, + R.bool.config_cecPowerControlModeNone_default); + + Setting powerStateChangeOnActiveSourceLost = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, + R.bool.config_cecPowerStateChangeOnActiveSourceLost_userConfigurable); + powerStateChangeOnActiveSourceLost.registerValue( + HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE, + R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_allowed, + R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_default); + powerStateChangeOnActiveSourceLost.registerValue( + HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW, + R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed, + R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default); + + Setting systemAudioModeMuting = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, + R.bool.config_cecSystemAudioModeMuting_userConfigurable); + systemAudioModeMuting.registerValue(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_ENABLED, + R.bool.config_cecSystemAudioModeMutingEnabled_allowed, + R.bool.config_cecSystemAudioModeMutingEnabled_default); + systemAudioModeMuting.registerValue(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED, + R.bool.config_cecSystemAudioModeMutingDisabled_allowed, + R.bool.config_cecSystemAudioModeMutingDisabled_default); + + Setting volumeControlMode = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + R.bool.config_cecVolumeControlMode_userConfigurable); + volumeControlMode.registerValue(HdmiControlManager.VOLUME_CONTROL_ENABLED, + R.bool.config_cecVolumeControlModeEnabled_allowed, + R.bool.config_cecVolumeControlModeEnabled_default); + volumeControlMode.registerValue(HdmiControlManager.VOLUME_CONTROL_DISABLED, + R.bool.config_cecVolumeControlModeDisabled_allowed, + R.bool.config_cecVolumeControlModeDisabled_default); + + Setting tvWakeOnOneTouchPlay = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY, + R.bool.config_cecTvWakeOnOneTouchPlay_userConfigurable); + tvWakeOnOneTouchPlay.registerValue(HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED, + R.bool.config_cecTvWakeOnOneTouchPlayEnabled_allowed, + R.bool.config_cecTvWakeOnOneTouchPlayEnabled_default); + tvWakeOnOneTouchPlay.registerValue(HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED, + R.bool.config_cecTvWakeOnOneTouchPlayDisabled_allowed, + R.bool.config_cecTvWakeOnOneTouchPlayDisabled_default); + + Setting tvSendStandbyOnSleep = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + R.bool.config_cecTvSendStandbyOnSleep_userConfigurable); + tvSendStandbyOnSleep.registerValue(HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED, + R.bool.config_cecTvSendStandbyOnSleepEnabled_allowed, + R.bool.config_cecTvSendStandbyOnSleepEnabled_default); + tvSendStandbyOnSleep.registerValue(HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_DISABLED, + R.bool.config_cecTvSendStandbyOnSleepDisabled_allowed, + R.bool.config_cecTvSendStandbyOnSleepDisabled_default); + + Setting rcProfileTv = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV, + R.bool.config_cecRcProfileTv_userConfigurable); + rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_NONE, + R.bool.config_cecRcProfileTvNone_allowed, + R.bool.config_cecRcProfileTvNone_default); + rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_ONE, + R.bool.config_cecRcProfileTvOne_allowed, + R.bool.config_cecRcProfileTvOne_default); + rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_TWO, + R.bool.config_cecRcProfileTvTwo_allowed, + R.bool.config_cecRcProfileTvTwo_default); + rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_THREE, + R.bool.config_cecRcProfileTvThree_allowed, + R.bool.config_cecRcProfileTvThree_default); + rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_FOUR, + R.bool.config_cecRcProfileTvFour_allowed, + R.bool.config_cecRcProfileTvFour_default); + + Setting rcProfileSourceRootMenu = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU, + R.bool.config_cecRcProfileSourceRootMenu_userConfigurable); + rcProfileSourceRootMenu.registerValue( + HdmiControlManager.RC_PROFILE_SOURCE_ROOT_MENU_HANDLED, + R.bool.config_cecRcProfileSourceRootMenuHandled_allowed, + R.bool.config_cecRcProfileSourceRootMenuHandled_default); + rcProfileSourceRootMenu.registerValue( + HdmiControlManager.RC_PROFILE_SOURCE_ROOT_MENU_NOT_HANDLED, + R.bool.config_cecRcProfileSourceRootMenuNotHandled_allowed, + R.bool.config_cecRcProfileSourceRootMenuNotHandled_default); + + Setting rcProfileSourceSetupMenu = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU, + R.bool.config_cecRcProfileSourceSetupMenu_userConfigurable); + rcProfileSourceSetupMenu.registerValue( + HdmiControlManager.RC_PROFILE_SOURCE_SETUP_MENU_HANDLED, + R.bool.config_cecRcProfileSourceSetupMenuHandled_allowed, + R.bool.config_cecRcProfileSourceSetupMenuHandled_default); + rcProfileSourceSetupMenu.registerValue( + HdmiControlManager.RC_PROFILE_SOURCE_SETUP_MENU_NOT_HANDLED, + R.bool.config_cecRcProfileSourceSetupMenuNotHandled_allowed, + R.bool.config_cecRcProfileSourceSetupMenuNotHandled_default); + + Setting rcProfileSourceContentsMenu = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU, + R.bool.config_cecRcProfileSourceContentsMenu_userConfigurable); + rcProfileSourceContentsMenu.registerValue( + HdmiControlManager.RC_PROFILE_SOURCE_CONTENTS_MENU_HANDLED, + R.bool.config_cecRcProfileSourceContentsMenuHandled_allowed, + R.bool.config_cecRcProfileSourceContentsMenuHandled_default); + rcProfileSourceContentsMenu.registerValue( + HdmiControlManager.RC_PROFILE_SOURCE_CONTENTS_MENU_NOT_HANDLED, + R.bool.config_cecRcProfileSourceContentsMenuNotHandled_allowed, + R.bool.config_cecRcProfileSourceContentsMenuNotHandled_default); + + Setting rcProfileSourceTopMenu = registerSetting( + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU, + R.bool.config_cecRcProfileSourceTopMenu_userConfigurable); + rcProfileSourceTopMenu.registerValue( + HdmiControlManager.RC_PROFILE_SOURCE_TOP_MENU_HANDLED, + R.bool.config_cecRcProfileSourceTopMenuHandled_allowed, + R.bool.config_cecRcProfileSourceTopMenuHandled_default); + rcProfileSourceTopMenu.registerValue( + HdmiControlManager.RC_PROFILE_SOURCE_TOP_MENU_NOT_HANDLED, + R.bool.config_cecRcProfileSourceTopMenuNotHandled_allowed, + R.bool.config_cecRcProfileSourceTopMenuNotHandled_default); + + Setting rcProfileSourceMediaContextSensitiveMenu = registerSetting( + HdmiControlManager + .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU, + R.bool.config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable); + rcProfileSourceMediaContextSensitiveMenu.registerValue( + HdmiControlManager.RC_PROFILE_SOURCE_MEDIA_CONTEXT_SENSITIVE_MENU_HANDLED, + R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed, + R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default); + rcProfileSourceMediaContextSensitiveMenu.registerValue( + HdmiControlManager.RC_PROFILE_SOURCE_MEDIA_CONTEXT_SENSITIVE_MENU_NOT_HANDLED, + R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed, + R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default); + + verifySettings(); + } + + HdmiCecConfig(@NonNull Context context) { + this(context, new StorageAdapter(context)); + } + + private Setting registerSetting(@NonNull @CecSettingName String name, + int userConfResId) { + Setting setting = new Setting(mContext, name, userConfResId); + mSettings.put(name, setting); + return setting; + } + + private void verifySettings() { + for (Setting setting: mSettings.values()) { + // This will throw an exception when a setting + // doesn't have a default value assigned. + setting.getDefaultValue(); + getStorage(setting); + getStorageKey(setting); + } + } + + @Nullable + private Setting getSetting(@NonNull String name) { + return mSettings.containsKey(name) ? mSettings.get(name) : null; } @Storage @@ -322,7 +524,7 @@ public class HdmiCecConfig { .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU: return STORAGE_SHARED_PREFS; default: - throw new RuntimeException("Invalid CEC setting '" + setting.getName() + throw new VerificationException("Invalid CEC setting '" + setting.getName() + "' storage."); } } @@ -359,7 +561,7 @@ public class HdmiCecConfig { .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU: return setting.getName(); default: - throw new RuntimeException("Invalid CEC setting '" + setting.getName() + throw new VerificationException("Invalid CEC setting '" + setting.getName() + "' storage key."); } } @@ -396,10 +598,6 @@ public class HdmiCecConfig { } } - private int getIntValue(@NonNull Value value) { - return Integer.decode(value.getIntValue()); - } - private void notifyGlobalSettingChanged(String setting) { switch (setting) { case Global.HDMI_CONTROL_ENABLED: @@ -533,41 +731,20 @@ public class HdmiCecConfig { * Returns a list of all settings based on the XML metadata. */ public @CecSettingName List<String> getAllSettings() { - if (mSystemConfig == null) { - return new ArrayList<String>(); - } - List<String> allSettings = new ArrayList<String>(); - for (Setting setting : mSystemConfig.getSetting()) { - allSettings.add(setting.getName()); - } - return allSettings; + return new ArrayList<>(mSettings.keySet()); } /** * Returns a list of user-modifiable settings based on the XML metadata. */ public @CecSettingName List<String> getUserSettings() { - if (mSystemConfig == null) { - return new ArrayList<String>(); - } - Set<String> userSettings = new HashSet<String>(); - // First read from the system config. - for (Setting setting : mSystemConfig.getSetting()) { + List<String> settings = new ArrayList<>(); + for (Setting setting: mSettings.values()) { if (setting.getUserConfigurable()) { - userSettings.add(setting.getName()); - } - } - if (mVendorOverride != null) { - // Next either add or remove based on the vendor override. - for (Setting setting : mVendorOverride.getSetting()) { - if (setting.getUserConfigurable()) { - userSettings.add(setting.getName()); - } else { - userSettings.remove(setting.getName()); - } + settings.add(setting.getName()); } } - return new ArrayList(userSettings); + return settings; } /** @@ -607,7 +784,7 @@ public class HdmiCecConfig { + "' is not a string-type setting."); } List<String> allowedValues = new ArrayList<String>(); - for (Value allowedValue : setting.getAllowedValues().getValue()) { + for (Value allowedValue : setting.getAllowedValues()) { allowedValues.add(allowedValue.getStringValue()); } return allowedValues; @@ -626,8 +803,8 @@ public class HdmiCecConfig { + "' is not a string-type setting."); } List<Integer> allowedValues = new ArrayList<Integer>(); - for (Value allowedValue : setting.getAllowedValues().getValue()) { - allowedValues.add(getIntValue(allowedValue)); + for (Value allowedValue : setting.getAllowedValues()) { + allowedValues.add(allowedValue.getIntValue()); } return allowedValues; } @@ -659,7 +836,7 @@ public class HdmiCecConfig { throw new IllegalArgumentException("Setting '" + name + "' is not a string-type setting."); } - return getIntValue(getSetting(name).getDefaultValue()); + return getSetting(name).getDefaultValue().getIntValue(); } /** @@ -691,7 +868,7 @@ public class HdmiCecConfig { + "' is not a int-type setting."); } HdmiLogger.debug("Getting CEC setting value '" + name + "'."); - String defaultValue = Integer.toString(getIntValue(setting.getDefaultValue())); + String defaultValue = Integer.toString(setting.getDefaultValue().getIntValue()); String value = retrieveValue(setting, defaultValue); return Integer.parseInt(value); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index d8914b389191..bdc4e66cf7f9 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -500,7 +500,8 @@ abstract class HdmiCecLocalDevice { HdmiDeviceInfo cecDeviceInfo = mService.getHdmiCecNetwork().getCecDeviceInfo(address); // If no non-default display name is available for the device, request the devices OSD name. - if (cecDeviceInfo.getDisplayName().equals(HdmiUtils.getDefaultDeviceName(address))) { + if (cecDeviceInfo != null && cecDeviceInfo.getDisplayName().equals( + HdmiUtils.getDefaultDeviceName(address))) { mService.sendCecCommand( HdmiCecMessageBuilder.buildGiveOsdNameCommand(mAddress, address)); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 7235a921254d..90d64339eac0 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -30,6 +30,7 @@ import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_ANAL import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL; import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL; +import android.annotation.Nullable; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPortInfo; @@ -1147,6 +1148,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { && getAvrDeviceInfo() != null; } + @Nullable @ServiceThreadOnly HdmiDeviceInfo getAvrDeviceInfo() { assertRunOnServiceThread(); @@ -1157,6 +1159,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return getSafeAvrDeviceInfo() != null; } + @Nullable HdmiDeviceInfo getSafeAvrDeviceInfo() { return mService.getHdmiCecNetwork().getSafeCecDeviceInfo(Constants.ADDR_AUDIO_SYSTEM); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java index b748ae026cfc..7ceaa959212e 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java @@ -185,6 +185,12 @@ public class HdmiCecNetwork { mLocalDevices.clear(); } + /** + * Get the device info of a local device or a device in the CEC network by a device id. + * @param id id of the device to get + * @return the device with the given id, or {@code null} + */ + @Nullable public HdmiDeviceInfo getDeviceInfo(int id) { return mDeviceInfos.get(id); } @@ -717,6 +723,7 @@ public class HdmiCecNetwork { * @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}. * Returns null if no logical address matched */ + @Nullable HdmiDeviceInfo getSafeCecDeviceInfo(int logicalAddress) { for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { if (info.isCecDevice() && info.getLogicalAddress() == logicalAddress) { diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 115cafedca93..e6e2f9631d45 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -988,6 +988,7 @@ public class HdmiControlService extends SystemService { return mCecController.getVendorId(); } + @Nullable @ServiceThreadOnly HdmiDeviceInfo getDeviceInfo(int logicalAddress) { assertRunOnServiceThread(); diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java index 02b09b15b464..9d2db94cac8e 100644 --- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java +++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java @@ -16,10 +16,12 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback; import android.hardware.hdmi.IHdmiControlCallback; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; /** * Feature action that performs one touch play against TV/Display device. This action is initiated @@ -40,13 +42,15 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { // standby mode, and do not accept the command until their power status becomes 'ON'. // For a workaround, we send <Give Device Power Status> commands periodically to make sure // the device switches its status to 'ON'. Then we send additional <Active Source>. - private static final int STATE_WAITING_FOR_REPORT_POWER_STATUS = 1; + @VisibleForTesting + static final int STATE_WAITING_FOR_REPORT_POWER_STATUS = 1; // The maximum number of times we send <Give Device Power Status> before we give up. // We wait up to RESPONSE_TIMEOUT_MS * LOOP_COUNTER_MAX = 20 seconds. private static final int LOOP_COUNTER_MAX = 10; private final int mTargetAddress; + private final boolean mIsCec20; private int mPowerStatusCounter = 0; @@ -59,14 +63,24 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { Slog.e(TAG, "Wrong arguments"); return null; } - return new OneTouchPlayAction(source, targetAddress, - callback); + return new OneTouchPlayAction(source, targetAddress, callback); } private OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress, IHdmiControlCallback callback) { + this(localDevice, targetAddress, callback, + localDevice.getDeviceInfo().getCecVersion() + >= HdmiControlManager.HDMI_CEC_VERSION_2_0 + && getTargetCecVersion(localDevice, targetAddress) + >= HdmiControlManager.HDMI_CEC_VERSION_2_0); + } + + @VisibleForTesting + OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress, + IHdmiControlCallback callback, boolean isCec20) { super(localDevice, callback); mTargetAddress = targetAddress; + mIsCec20 = isCec20; } @Override @@ -74,6 +88,9 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { // Because only source device can create this action, it's safe to cast. mSource = source(); sendCommand(HdmiCecMessageBuilder.buildTextViewOn(getSourceAddress(), mTargetAddress)); + + boolean targetOnBefore = getTargetDevicePowerStatus(mSource, mTargetAddress, + HdmiControlManager.POWER_STATUS_UNKNOWN) == HdmiControlManager.POWER_STATUS_ON; broadcastActiveSource(); // If the device is not an audio system itself, request the connected audio system to // turn on. @@ -81,7 +98,20 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { sendCommand(HdmiCecMessageBuilder.buildSystemAudioModeRequest(getSourceAddress(), Constants.ADDR_AUDIO_SYSTEM, getSourcePath(), true)); } - queryDevicePowerStatus(); + int targetPowerStatus = getTargetDevicePowerStatus(mSource, mTargetAddress, + HdmiControlManager.POWER_STATUS_UNKNOWN); + if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) { + queryDevicePowerStatus(); + } else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) { + if (!targetOnBefore) { + // Suppress 2nd <Active Source> message if the target device was already on when + // the 1st one was sent. + broadcastActiveSource(); + } + finishWithCallback(HdmiControlManager.RESULT_SUCCESS); + return true; + } + mState = STATE_WAITING_FOR_REPORT_POWER_STATUS; addTimer(mState, HdmiConfig.TIMEOUT_MS); return true; } @@ -101,7 +131,6 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { } private void queryDevicePowerStatus() { - mState = STATE_WAITING_FOR_REPORT_POWER_STATUS; sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), mTargetAddress)); } @@ -150,4 +179,23 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { return sendStandbyOnSleep.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST); } + private static int getTargetCecVersion(HdmiCecLocalDevice localDevice, + int targetLogicalAddress) { + HdmiDeviceInfo targetDevice = localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo( + targetLogicalAddress); + if (targetDevice != null) { + return targetDevice.getCecVersion(); + } + return HdmiControlManager.HDMI_CEC_VERSION_1_4_B; + } + + private static int getTargetDevicePowerStatus(HdmiCecLocalDevice localDevice, + int targetLogicalAddress, int defaultPowerStatus) { + HdmiDeviceInfo targetDevice = localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo( + targetLogicalAddress); + if (targetDevice != null) { + return targetDevice.getDevicePowerStatus(); + } + return defaultPowerStatus; + } } diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java index f7e871d0b645..56e538b1abfa 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java @@ -17,6 +17,8 @@ package com.android.server.hdmi; import android.hardware.tv.cec.V1_0.SendMessageResult; + +import com.android.internal.annotations.VisibleForTesting; import com.android.server.hdmi.HdmiControlService.SendMessageCallback; /** @@ -30,6 +32,14 @@ final class SystemAudioAutoInitiationAction extends HdmiCecFeatureAction { // <Give System Audio Mode Status> to AV Receiver. private static final int STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS = 1; + @VisibleForTesting + static final int RETRIES_ON_TIMEOUT = 1; + + // On some audio devices the <System Audio Mode Status> message can be delayed as the device + // is just waking up. Retry the <Give System Audio Mode Status> message to ensure we properly + // initialize system audio. + private int mRetriesOnTimeOut = RETRIES_ON_TIMEOUT; + SystemAudioAutoInitiationAction(HdmiCecLocalDevice source, int avrAddress) { super(source); mAvrAddress = avrAddress; @@ -100,6 +110,13 @@ final class SystemAudioAutoInitiationAction extends HdmiCecFeatureAction { switch (mState) { case STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS: + if (mRetriesOnTimeOut > 0) { + mRetriesOnTimeOut--; + addTimer(mState, HdmiConfig.TIMEOUT_MS); + sendGiveSystemAudioModeStatus(); + return; + } + handleSystemAudioModeStatusTimeout(); break; } diff --git a/services/core/java/com/android/server/hdmi/cec_config.xml b/services/core/java/com/android/server/hdmi/cec_config.xml deleted file mode 100644 index 191e725181ca..000000000000 --- a/services/core/java/com/android/server/hdmi/cec_config.xml +++ /dev/null @@ -1,133 +0,0 @@ -<?xml version='1.0' encoding='utf-8' standalone='yes' ?> -<cec-settings> - <setting name="hdmi_cec_enabled" - value-type="int" - user-configurable="true"> - <allowed-values> - <value int-value="0" /> - <value int-value="1" /> - </allowed-values> - <default-value int-value="1" /> - </setting> - <setting name="hdmi_cec_version" - value-type="int" - user-configurable="true"> - <allowed-values> - <value int-value="0x05" /> - <value int-value="0x06" /> - </allowed-values> - <default-value int-value="0x05" /> - </setting> - <setting name="send_standby_on_sleep" - value-type="string" - user-configurable="true"> - <allowed-values> - <value string-value="to_tv" /> - <value string-value="broadcast" /> - <value string-value="none" /> - </allowed-values> - <default-value string-value="to_tv" /> - </setting> - <setting name="power_state_change_on_active_source_lost" - value-type="string" - user-configurable="true"> - <allowed-values> - <value string-value="none" /> - <value string-value="standby_now" /> - </allowed-values> - <default-value string-value="none" /> - </setting> - <setting name="system_audio_mode_muting" - value-type="int" - user-configurable="true"> - <allowed-values> - <value int-value="0" /> - <value int-value="1" /> - </allowed-values> - <default-value int-value="1" /> - </setting> - <setting name="volume_control_enabled" - value-type="int" - user-configurable="true"> - <allowed-values> - <value int-value="0" /> - <value int-value="1" /> - </allowed-values> - <default-value int-value="1" /> - </setting> - <setting name="tv_wake_on_one_touch_play" - value-type="int" - user-configurable="true"> - <allowed-values> - <value int-value="0" /> - <value int-value="1" /> - </allowed-values> - <default-value int-value="1" /> - </setting> - <setting name="tv_send_standby_on_sleep" - value-type="int" - user-configurable="true"> - <allowed-values> - <value int-value="0" /> - <value int-value="1" /> - </allowed-values> - <default-value int-value="1" /> - </setting> - <setting name="rc_profile_tv" - value-type="int" - user-configurable="false"> - <allowed-values> - <value int-value="0x0" /> - <value int-value="0x2" /> - <value int-value="0x6" /> - <value int-value="0xA" /> - <value int-value="0xE" /> - </allowed-values> - <default-value int-value="0x0" /> - </setting> - <setting name="rc_profile_source_handles_root_menu" - value-type="int" - user-configurable="false"> - <allowed-values> - <value int-value="0" /> - <value int-value="1" /> - </allowed-values> - <default-value int-value="1" /> - </setting> - <setting name="rc_profile_source_handles_setup_menu" - value-type="int" - user-configurable="false"> - <allowed-values> - <value int-value="0" /> - <value int-value="1" /> - </allowed-values> - <default-value int-value="1" /> - </setting> - <setting name="rc_profile_source_handles_contents_menu" - value-type="int" - user-configurable="false"> - <allowed-values> - <value int-value="0" /> - <value int-value="1" /> - </allowed-values> - <default-value int-value="0" /> - </setting> - <setting name="rc_profile_source_handles_top_menu" - value-type="int" - user-configurable="false"> - <allowed-values> - <value int-value="0" /> - <value int-value="1" /> - </allowed-values> - <default-value int-value="0" /> - </setting> - <setting name="rc_profile_source_handles_media_context_sensitive_menu" - value-type="int" - user-configurable="false"> - <allowed-values> - <value int-value="0" /> - <value int-value="1" /> - </allowed-values> - <default-value int-value="0" /> - </setting> -</cec-settings> diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index edb5d97f1a5a..cbe6e69cbef3 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -304,7 +304,7 @@ public class InputManagerService extends IInputManager.Stub int displayId, InputApplicationHandle application); private static native void nativeSetFocusedDisplay(long ptr, int displayId); private static native boolean nativeTransferTouchFocus(long ptr, - IBinder fromChannelToken, IBinder toChannelToken); + IBinder fromChannelToken, IBinder toChannelToken, boolean isDragDrop); private static native void nativeSetPointerSpeed(long ptr, int speed); private static native void nativeSetShowTouches(long ptr, boolean enabled); private static native void nativeSetInteractive(long ptr, boolean interactive); @@ -586,18 +586,13 @@ public class InputManagerService extends IInputManager.Stub private void setDisplayViewportsInternal(List<DisplayViewport> viewports) { final DisplayViewport[] vArray = new DisplayViewport[viewports.size()]; if (ENABLE_PER_WINDOW_INPUT_ROTATION) { - // Remove all viewport operations. They will be built-into the window transforms. + // Remove display projection information from DisplayViewport, leaving only the + // orientation. The display projection will be built-into the window transforms. for (int i = viewports.size() - 1; i >= 0; --i) { final DisplayViewport v = vArray[i] = viewports.get(i).makeCopy(); - // deviceWidth/Height are apparently in "rotated" space, so flip them if needed. - if (v.orientation % 2 != 0) { - final int dw = v.deviceWidth; - v.deviceWidth = v.deviceHeight; - v.deviceHeight = dw; - } + // Note: the deviceWidth/Height are in rotated with the orientation. v.logicalFrame.set(0, 0, v.deviceWidth, v.deviceHeight); v.physicalFrame.set(0, 0, v.deviceWidth, v.deviceHeight); - v.orientation = 0; } } else { for (int i = viewports.size() - 1; i >= 0; --i) { @@ -1732,12 +1727,14 @@ public class InputManagerService extends IInputManager.Stub * @param fromChannel The channel of a window that currently has touch focus. * @param toChannel The channel of the window that should receive touch focus in * place of the first. + * @param isDragDrop True if transfer touch focus for drag and drop. * @return True if the transfer was successful. False if the window with the * specified channel did not actually have touch focus at the time of the request. */ public boolean transferTouchFocus(@NonNull InputChannel fromChannel, - @NonNull InputChannel toChannel) { - return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken()); + @NonNull InputChannel toChannel, boolean isDragDrop) { + return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken(), + isDragDrop); } /** @@ -1757,7 +1754,8 @@ public class InputManagerService extends IInputManager.Stub @NonNull IBinder toChannelToken) { Objects.nonNull(fromChannelToken); Objects.nonNull(toChannelToken); - return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken); + return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken, + false /* isDragDrop */); } @Override // Binder call diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 8285e32ed8db..672ed3d00344 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2621,8 +2621,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken); // Dispatch display id for InputMethodService to update context display. - executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO( - MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken)); + executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO( + MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken, + mMethodMap.get(mCurMethodId).getConfigChanges())); scheduleNotifyImeUidToAudioService(mCurMethodUid); if (mCurClient != null) { clearClientSessionLocked(mCurClient); @@ -4478,7 +4479,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } final IBinder token = (IBinder) args.arg2; ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1, - new InputMethodPrivilegedOperationsImpl(this, token)); + new InputMethodPrivilegedOperationsImpl(this, token), + (int) args.arg3); } catch (RemoteException e) { } args.recycle(); @@ -5836,7 +5838,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @BinderThread @ShellCommandResult private int handleShellCommandTraceInputMethod(@NonNull ShellCommand shellCommand) { - int result = ImeTracing.getInstance().onShellCommand(shellCommand); + final String cmd = shellCommand.getNextArgRequired(); + final PrintWriter pw = shellCommand.getOutPrintWriter(); + switch (cmd) { + case "start": + ImeTracing.getInstance().getInstance().startTrace(pw); + break; + case "stop": + ImeTracing.getInstance().stopTrace(pw); + break; + default: + pw.println("Unknown command: " + cmd); + pw.println("Input method trace options:"); + pw.println(" start: Start tracing"); + pw.println(" stop: Stop tracing"); + return ShellCommandResult.FAILURE; + } boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled(); ArrayMap<IBinder, ClientState> clients; synchronized (mMethodMap) { @@ -5852,7 +5869,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } } - return result; + return ShellCommandResult.SUCCESS; } /** diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java index 5a90fa7a271c..7f47805ee121 100644 --- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java +++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java @@ -370,6 +370,7 @@ public class GeofenceManager extends LocationStatsEnums.USAGE_ENDED, LocationStatsEnums.API_REQUEST_GEOFENCE, registration.getIdentity().getPackageName(), + registration.getIdentity().getAttributionTag(), null, /* LocationRequest= */ null, /* hasListener= */ false, @@ -383,6 +384,7 @@ public class GeofenceManager extends LocationStatsEnums.USAGE_ENDED, LocationStatsEnums.API_REQUEST_GEOFENCE, registration.getIdentity().getPackageName(), + registration.getIdentity().getAttributionTag(), null, /* LocationRequest= */ null, /* hasListener= */ false, diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java index b3119d7aa53e..8460d6797543 100644 --- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java @@ -189,6 +189,7 @@ public final class GnssMeasurementsProvider extends LocationStatsEnums.USAGE_STARTED, LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER, registration.getIdentity().getPackageName(), + registration.getIdentity().getAttributionTag(), null, null, true, @@ -202,6 +203,7 @@ public final class GnssMeasurementsProvider extends LocationStatsEnums.USAGE_ENDED, LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER, registration.getIdentity().getPackageName(), + registration.getIdentity().getAttributionTag(), null, null, true, diff --git a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java index 1eb16184685d..936283deda8e 100644 --- a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java @@ -83,6 +83,7 @@ public class GnssStatusProvider extends LocationStatsEnums.USAGE_STARTED, LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK, registration.getIdentity().getPackageName(), + registration.getIdentity().getAttributionTag(), null, null, true, @@ -96,6 +97,7 @@ public class GnssStatusProvider extends LocationStatsEnums.USAGE_ENDED, LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK, registration.getIdentity().getPackageName(), + registration.getIdentity().getAttributionTag(), null, null, true, diff --git a/services/core/java/com/android/server/location/injector/LocationUsageLogger.java b/services/core/java/com/android/server/location/injector/LocationUsageLogger.java index 244a8e0daca0..af21bcbfb0ef 100644 --- a/services/core/java/com/android/server/location/injector/LocationUsageLogger.java +++ b/services/core/java/com/android/server/location/injector/LocationUsageLogger.java @@ -49,9 +49,9 @@ public class LocationUsageLogger { * Log a location API usage event. */ public void logLocationApiUsage(int usageType, int apiInUse, - String packageName, String provider, LocationRequest locationRequest, - boolean hasListener, boolean hasIntent, - Geofence geofence, boolean foreground) { + String packageName, String attributionTag, String provider, + LocationRequest locationRequest, boolean hasListener, + boolean hasIntent, Geofence geofence, boolean foreground) { try { if (hitApiUsageLogCap()) { return; @@ -84,7 +84,8 @@ public class LocationUsageLogger { isGeofenceNull ? LocationStatsEnums.RADIUS_UNKNOWN : bucketizeRadius(geofence.getRadius()), - categorizeActivityImportance(foreground)); + categorizeActivityImportance(foreground), + attributionTag); } catch (Exception e) { // Swallow exceptions to avoid crashing LMS. Log.w(TAG, "Failed to log API usage to statsd.", e); @@ -114,7 +115,8 @@ public class LocationUsageLogger { /* isListenerNull= */ true, /* isIntentNull= */ true), /* bucketizedRadius= */ 0, - LocationStatsEnums.IMPORTANCE_UNKNOWN); + LocationStatsEnums.IMPORTANCE_UNKNOWN, + /* attribution_tag */ null); } catch (Exception e) { Log.w(TAG, "Failed to log API usage to statsd.", e); } diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java index dbd8dd9eff3b..aa3e5795b684 100644 --- a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java +++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java @@ -82,7 +82,7 @@ public class SystemEmergencyHelper extends EmergencyHelper { TelephonyCallback.CallStateListener{ @Override - public void onCallStateChanged(int state, String incomingNumber) { + public void onCallStateChanged(int state) { if (state == TelephonyManager.CALL_STATE_IDLE) { if (mIsInEmergencyCall) { mEmergencyCallEndRealtimeMs = SystemClock.elapsedRealtime(); diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index 2aa6f2869afb..dc8b1d001c74 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -1854,6 +1854,7 @@ public class LocationProviderManager extends LocationStatsEnums.USAGE_STARTED, LocationStatsEnums.API_REQUEST_LOCATION_UPDATES, registration.getIdentity().getPackageName(), + registration.getIdentity().getAttributionTag(), mName, registration.getRequest(), key instanceof PendingIntent, @@ -1882,6 +1883,7 @@ public class LocationProviderManager extends LocationStatsEnums.USAGE_ENDED, LocationStatsEnums.API_REQUEST_LOCATION_UPDATES, registration.getIdentity().getPackageName(), + registration.getIdentity().getAttributionTag(), mName, registration.getRequest(), key instanceof PendingIntent, diff --git a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java index 82b0f9c05b6b..6d250ecb9fa4 100644 --- a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java +++ b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java @@ -135,7 +135,11 @@ public class BiometricDeferredQueue { } sensorIds.remove(sensorId); - faceManager.revokeChallenge(sensorId); + // Challenge is only required for IBiometricsFace@1.0 (and not IFace AIDL). The + // IBiometricsFace@1.0 HAL does not require userId to revokeChallenge, so passing + // in 0 is OK. + final int userId = 0; + faceManager.revokeChallenge(sensorId, userId, challenge); if (sensorIds.isEmpty()) { Slog.d(TAG, "Done requesting resetLockout for all face sensors"); diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index 48382a946d4b..6e99cba6ea91 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -64,6 +64,8 @@ class RebootEscrowManager { @VisibleForTesting public static final String REBOOT_ESCROW_ARMED_KEY = "reboot_escrow_armed_count"; + static final String REBOOT_ESCROW_KEY_ARMED_TIMESTAMP = "reboot_escrow_key_stored_timestamp"; + /** * Number of boots until we consider the escrow data to be stale for the purposes of metrics. * <p> @@ -144,8 +146,7 @@ class RebootEscrowManager { private RebootEscrowProviderInterface createRebootEscrowProvider() { RebootEscrowProviderInterface rebootEscrowProvider; - if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA, - "server_based_ror_enabled", false)) { + if (serverBasedResumeOnReboot()) { Slog.i(TAG, "Using server based resume on reboot"); rebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(mContext, mStorage); } else { @@ -166,6 +167,11 @@ class RebootEscrowManager { handler.postDelayed(runnable, delayMillis); } + public boolean serverBasedResumeOnReboot() { + return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA, + "server_based_ror_enabled", false); + } + public Context getContext() { return mContext; } @@ -204,10 +210,12 @@ class RebootEscrowManager { DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS); } - public void reportMetric(boolean success) { - // TODO(b/179105110) design error code; and report the true value for other fields. - FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, 0, 1, 1, - -1, 0, -1); + public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, + int escrowDurationInSeconds, int vbmetaDigestStatus, + int durationSinceBootCompleteInSeconds) { + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, success, + errorCode, serviceType, attemptCount, escrowDurationInSeconds, + vbmetaDigestStatus, durationSinceBootCompleteInSeconds); } public RebootEscrowEventLog getEventLog() { @@ -230,7 +238,7 @@ class RebootEscrowManager { mKeyStoreManager = injector.getKeyStoreManager(); } - private void onGetRebootEscrowKeyFailed(List<UserInfo> users) { + private void onGetRebootEscrowKeyFailed(List<UserInfo> users, int attemptCount) { Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage."); for (UserInfo user : users) { mStorage.removeRebootEscrow(user.id); @@ -238,7 +246,7 @@ class RebootEscrowManager { // Clear the old key in keystore. mKeyStoreManager.clearKeyStoreEncryptionKey(); - onEscrowRestoreComplete(false); + onEscrowRestoreComplete(false, attemptCount); } void loadRebootEscrowDataIfAvailable(Handler retryHandler) { @@ -251,6 +259,8 @@ class RebootEscrowManager { } if (rebootEscrowUsers.isEmpty()) { + Slog.i(TAG, "No reboot escrow data found for users," + + " skipping loading escrow data"); return; } @@ -274,7 +284,7 @@ class RebootEscrowManager { } Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts"); - onGetRebootEscrowKeyFailed(users); + onGetRebootEscrowKeyFailed(users, attemptNumber); } void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber, @@ -297,7 +307,7 @@ class RebootEscrowManager { } if (escrowKey == null) { - onGetRebootEscrowKeyFailed(users); + onGetRebootEscrowKeyFailed(users, attemptNumber + 1); return; } @@ -311,16 +321,35 @@ class RebootEscrowManager { // Clear the old key in keystore. A new key will be generated by new RoR requests. mKeyStoreManager.clearKeyStoreEncryptionKey(); - onEscrowRestoreComplete(allUsersUnlocked); + onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1); + } + + private void reportMetricOnRestoreComplete(boolean success, int attemptCount) { + int serviceType = mInjector.serverBasedResumeOnReboot() + ? FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__SERVER_BASED + : FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__HAL; + + long armedTimestamp = mStorage.getLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, -1, + USER_SYSTEM); + mStorage.removeKey(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, USER_SYSTEM); + int escrowDurationInSeconds = armedTimestamp != -1 + ? (int) (System.currentTimeMillis() - armedTimestamp) / 1000 : -1; + + // TODO(b/179105110) design error code; and report the true value for other fields. + int vbmetaDigestStatus = FrameworkStatsLog + .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT; + + mInjector.reportMetric(success, 0 /* error code */, serviceType, attemptCount, + escrowDurationInSeconds, vbmetaDigestStatus, -1); } - private void onEscrowRestoreComplete(boolean success) { + private void onEscrowRestoreComplete(boolean success, int attemptCount) { int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM); mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM); int bootCountDelta = mInjector.getBootCount() - previousBootCount; if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) { - mInjector.reportMetric(success); + reportMetricOnRestoreComplete(success, attemptCount); } } @@ -476,6 +505,8 @@ class RebootEscrowManager { boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk); if (armedRebootEscrow) { mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM); + mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, System.currentTimeMillis(), + USER_SYSTEM); mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS); } diff --git a/services/core/java/com/android/server/locksettings/TEST_MAPPING b/services/core/java/com/android/server/locksettings/TEST_MAPPING index c1cba5f7f22d..4a216ca90f9b 100644 --- a/services/core/java/com/android/server/locksettings/TEST_MAPPING +++ b/services/core/java/com/android/server/locksettings/TEST_MAPPING @@ -10,6 +10,17 @@ "exclude-annotation": "android.platform.test.annotations.FlakyTest" } ] + }, + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-filter": "com.android.server.locksettings." + }, + { + "exclude-annotation": "android.platform.test.annotations.FlakyTest" + } + ] } ] } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformDecryptionKey.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformDecryptionKey.java index 35571f1f2728..e75aae1f99aa 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformDecryptionKey.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformDecryptionKey.java @@ -16,7 +16,7 @@ package com.android.server.locksettings.recoverablekeystore; -import android.security.keystore.AndroidKeyStoreSecretKey; +import javax.crypto.SecretKey; /** * Used to unwrap recoverable keys before syncing them with remote storage. @@ -30,7 +30,7 @@ import android.security.keystore.AndroidKeyStoreSecretKey; public class PlatformDecryptionKey { private final int mGenerationId; - private final AndroidKeyStoreSecretKey mKey; + private final SecretKey mKey; /** * A new instance. @@ -40,7 +40,7 @@ public class PlatformDecryptionKey { * * @hide */ - public PlatformDecryptionKey(int generationId, AndroidKeyStoreSecretKey key) { + public PlatformDecryptionKey(int generationId, SecretKey key) { mGenerationId = generationId; mKey = key; } @@ -59,7 +59,7 @@ public class PlatformDecryptionKey { * * @hide */ - public AndroidKeyStoreSecretKey getKey() { + public SecretKey getKey() { return mKey; } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformEncryptionKey.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformEncryptionKey.java index 38f5b45ea190..ee334462f7be 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformEncryptionKey.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformEncryptionKey.java @@ -16,7 +16,7 @@ package com.android.server.locksettings.recoverablekeystore; -import android.security.keystore.AndroidKeyStoreSecretKey; +import javax.crypto.SecretKey; /** * Private key stored in AndroidKeyStore. Used to wrap recoverable keys before writing them to disk. @@ -33,7 +33,7 @@ import android.security.keystore.AndroidKeyStoreSecretKey; public class PlatformEncryptionKey { private final int mGenerationId; - private final AndroidKeyStoreSecretKey mKey; + private final SecretKey mKey; /** * A new instance. @@ -41,7 +41,7 @@ public class PlatformEncryptionKey { * @param generationId The generation ID of the key. * @param key The secret key handle. Can be used to encrypt WITHOUT requiring screen unlock. */ - public PlatformEncryptionKey(int generationId, AndroidKeyStoreSecretKey key) { + public PlatformEncryptionKey(int generationId, SecretKey key) { mGenerationId = generationId; mKey = key; } @@ -56,7 +56,7 @@ public class PlatformEncryptionKey { /** * Returns the actual key, which can only be used to encrypt. */ - public AndroidKeyStoreSecretKey getKey() { + public SecretKey getKey() { return mKey; } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java index f448a6ef8c0b..f32af5434c43 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java @@ -21,7 +21,6 @@ import android.content.Context; import android.os.RemoteException; import android.os.UserHandle; import android.security.GateKeeper; -import android.security.keystore.AndroidKeyStoreSecretKey; import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; @@ -237,7 +236,7 @@ public class PlatformKeyManager { if (!isKeyLoaded(userId, generationId)) { throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias); } - AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( + SecretKey key = (SecretKey) mKeyStore.getKey( alias, /*password=*/ null); return new PlatformEncryptionKey(generationId, key); } @@ -289,7 +288,7 @@ public class PlatformKeyManager { if (!isKeyLoaded(userId, generationId)) { throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias); } - AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( + SecretKey key = (SecretKey) mKeyStore.getKey( alias, /*password=*/ null); return new PlatformDecryptionKey(generationId, key); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 6f39fea5dd95..0cc9f9e150c6 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -134,7 +134,6 @@ import android.app.AlarmManager; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AutomaticZenRule; -import android.app.BroadcastOptions; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; @@ -6082,6 +6081,17 @@ public class NotificationManagerService extends SystemService { } } + // Ensure CallStyle has all the correct actions + if ("android.app.Notification$CallStyle".equals( + notification.extras.getString(Notification.EXTRA_TEMPLATE))) { + Notification.Builder builder = + Notification.Builder.recoverBuilder(getContext(), notification); + Notification.CallStyle style = (Notification.CallStyle) builder.getStyle(); + List<Notification.Action> actions = style.getActionsListWithSystemActions(); + notification.actions = new Notification.Action[actions.size()]; + actions.toArray(notification.actions); + } + // Remote views? Are they too big? checkRemoteViews(pkg, tag, id, notification); } diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java index 66ea55401cef..afce23fe7647 100644 --- a/services/core/java/com/android/server/pm/ApkChecksums.java +++ b/services/core/java/com/android/server/pm/ApkChecksums.java @@ -59,8 +59,8 @@ import android.util.apk.SignatureNotFoundException; import android.util.apk.VerityBuilder; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.security.VerityUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; -import com.android.server.security.VerityUtils; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index d3a56c6f67c0..044e186140a4 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -70,6 +70,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IInterface; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; @@ -114,6 +115,7 @@ public class LauncherAppsService extends SystemService { @Override public void onStart() { publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl); + mLauncherAppsImpl.registerLoadingProgressForIncrementalApps(); } static class BroadcastCookie { @@ -1184,6 +1186,30 @@ public class LauncherAppsService extends SystemService { mCallbackHandler.post(r); } + /** + * Check all installed apps and if a package is installed via Incremental and not fully + * loaded, register loading progress listener. + */ + void registerLoadingProgressForIncrementalApps() { + final PackageManagerInternal pmInt = + LocalServices.getService(PackageManagerInternal.class); + final List<UserHandle> users = mUm.getUserProfiles(); + if (users == null) { + return; + } + for (UserHandle user : users) { + pmInt.forEachInstalledPackage(pkg -> { + final String packageName = pkg.getPackageName(); + if (pmInt.getIncrementalStatesInfo(packageName, Process.myUid(), + user.getIdentifier()).isLoading()) { + pmInt.registerInstalledLoadingProgressCallback(packageName, + new PackageLoadingProgressCallback(packageName, user), + user.getIdentifier()); + } + }, user.getIdentifier()); + } + } + public static class ShortcutChangeHandler implements LauncherApps.ShortcutChangeCallback { private final UserManagerInternal mUserManagerInternal; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 903652ab76a5..82b12aac0a11 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -138,6 +138,7 @@ import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.os.SomeArgs; +import com.android.internal.security.VerityUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; @@ -146,7 +147,6 @@ import com.android.server.LocalServices; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.dex.DexManager; import com.android.server.pm.parsing.pkg.AndroidPackage; -import com.android.server.security.VerityUtils; import libcore.io.IoUtils; import libcore.util.EmptyArray; @@ -3060,7 +3060,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Also stage .dm.fsv_sig. .dm may be required to install with fs-verity signature on // supported on older devices. maybeStageFsveritySignatureLocked(dexMetadataFile, targetDexMetadataFile, - VerityUtils.isFsVeritySupported() && DexMetadataHelper.isFsVerityRequired()); + DexMetadataHelper.isFsVerityRequired()); } private void storeBytesToInstallationFile(final String localPath, final String absolutePath, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index a1da241c6642..f828a119f988 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -349,6 +349,7 @@ import com.android.internal.content.om.OverlayConfig; import com.android.internal.logging.MetricsLogger; import com.android.internal.os.SomeArgs; import com.android.internal.policy.AttributeCache; +import com.android.internal.security.VerityUtils; import com.android.internal.telephony.CarrierAppUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; @@ -401,7 +402,6 @@ import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy; import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1; import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2; import com.android.server.rollback.RollbackManagerInternal; -import com.android.server.security.VerityUtils; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.utils.TimingsTraceAndSlog; @@ -1979,6 +1979,8 @@ public class PackageManagerService extends IPackageManager.Stub @Nullable ComponentName component, @ComponentType int componentType, int userId); boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid, int userId); + boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid, + int userId); int bestDomainVerificationStatus(int status1, int status2); int checkUidPermission(String permName, int uid); int getPackageUidInternal(String packageName, int flags, int userId, int callingUid); @@ -4143,6 +4145,19 @@ public class PackageManagerService extends IPackageManager.Stub } /** + * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int) + */ + public boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid, + int userId) { + boolean filterApp = true; + for (int index = sus.packages.size() - 1; index >= 0 && filterApp; index--) { + filterApp &= shouldFilterApplicationLocked(sus.packages.valueAt(index), + callingUid, /* component */ null, TYPE_UNKNOWN, userId); + } + return filterApp; + } + + /** * Verification statuses are ordered from the worse to the best, except for * INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse. */ @@ -7904,6 +7919,15 @@ public class PackageManagerService extends IPackageManager.Stub ps, callingUid, userId); } + /** + * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int) + */ + @GuardedBy("mLock") + private boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid, + int userId) { + return liveComputer().shouldFilterApplicationLocked(sus, callingUid, userId); + } + @GuardedBy("mLock") private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId, int flags) { @@ -8970,7 +8994,6 @@ public class PackageManagerService extends IPackageManager.Stub public int checkUidSignatures(int uid1, int uid2) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null; // Map to base uids. final int appId1 = UserHandle.getAppId(uid1); final int appId2 = UserHandle.getAppId(uid2); @@ -8981,10 +9004,11 @@ public class PackageManagerService extends IPackageManager.Stub Object obj = mSettings.getSettingLPr(appId1); if (obj != null) { if (obj instanceof SharedUserSetting) { - if (isCallerInstantApp) { + final SharedUserSetting sus = (SharedUserSetting) obj; + if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - p1SigningDetails = ((SharedUserSetting) obj).signatures.mSigningDetails; + p1SigningDetails = sus.signatures.mSigningDetails; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { @@ -9000,10 +9024,11 @@ public class PackageManagerService extends IPackageManager.Stub obj = mSettings.getSettingLPr(appId2); if (obj != null) { if (obj instanceof SharedUserSetting) { - if (isCallerInstantApp) { + final SharedUserSetting sus = (SharedUserSetting) obj; + if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - p2SigningDetails = ((SharedUserSetting) obj).signatures.mSigningDetails; + p2SigningDetails = sus.signatures.mSigningDetails; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { @@ -9092,11 +9117,11 @@ public class PackageManagerService extends IPackageManager.Stub final Object obj = mSettings.getSettingLPr(appId); if (obj != null) { if (obj instanceof SharedUserSetting) { - final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null; - if (isCallerInstantApp) { + final SharedUserSetting sus = (SharedUserSetting) obj; + if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { return false; } - signingDetails = ((SharedUserSetting)obj).signatures.mSigningDetails; + signingDetails = sus.signatures.mSigningDetails; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { @@ -9221,16 +9246,19 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(callingUid) != null) { return null; } + final int callingUserId = UserHandle.getUserId(callingUid); final int appId = UserHandle.getAppId(uid); synchronized (mLock) { final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; + if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { + return null; + } return sus.name + ":" + sus.userId; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; - if (shouldFilterApplicationLocked( - ps, callingUid, UserHandle.getUserId(callingUid))) { + if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return null; } return ps.name; @@ -9248,6 +9276,7 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(callingUid) != null) { return null; } + final int callingUserId = UserHandle.getUserId(callingUid); final String[] names = new String[uids.length]; synchronized (mLock) { for (int i = uids.length - 1; i >= 0; i--) { @@ -9255,11 +9284,14 @@ public class PackageManagerService extends IPackageManager.Stub final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; - names[i] = "shared:" + sus.name; + if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { + names[i] = null; + } else { + names[i] = "shared:" + sus.name; + } } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; - if (shouldFilterApplicationLocked( - ps, callingUid, UserHandle.getUserId(callingUid))) { + if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { names[i] = null; } else { names[i] = ps.name; @@ -9301,16 +9333,19 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(callingUid) != null) { return 0; } + final int callingUserId = UserHandle.getUserId(callingUid); final int appId = UserHandle.getAppId(uid); synchronized (mLock) { final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; + if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { + return 0; + } return sus.pkgFlags; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; - if (shouldFilterApplicationLocked( - ps, callingUid, UserHandle.getUserId(callingUid))) { + if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return 0; } return ps.pkgFlags; @@ -9325,16 +9360,19 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(callingUid) != null) { return 0; } + final int callingUserId = UserHandle.getUserId(callingUid); final int appId = UserHandle.getAppId(uid); synchronized (mLock) { final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; + if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { + return 0; + } return sus.pkgPrivateFlags; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; - if (shouldFilterApplicationLocked( - ps, callingUid, UserHandle.getUserId(callingUid))) { + if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return 0; } return ps.pkgPrivateFlags; @@ -27765,13 +27803,23 @@ public class PackageManagerService extends IPackageManager.Stub } private static String getDefaultTimeouts() { - return DeviceConfig.getString(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, - PROPERTY_INCFS_DEFAULT_TIMEOUTS, ""); + final long token = Binder.clearCallingIdentity(); + try { + return DeviceConfig.getString(NAMESPACE_PACKAGE_MANAGER_SERVICE, + PROPERTY_INCFS_DEFAULT_TIMEOUTS, ""); + } finally { + Binder.restoreCallingIdentity(token); + } } private static String getKnownDigestersList() { - return DeviceConfig.getString(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, - PROPERTY_KNOWN_DIGESTERS_LIST, ""); + final long token = Binder.clearCallingIdentity(); + try { + return DeviceConfig.getString(NAMESPACE_PACKAGE_MANAGER_SERVICE, + PROPERTY_KNOWN_DIGESTERS_LIST, ""); + } finally { + Binder.restoreCallingIdentity(token); + } } /** diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index d1cf55de7254..38cba4ca9e20 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -1889,231 +1889,248 @@ public class ShortcutService extends IShortcutService.Stub { @Override public void setDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, @UserIdInt int userId, @NonNull AndroidFuture callback) { - verifyCaller(packageName, userId); + try { + verifyCaller(packageName, userId); - final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); - verifyShortcutInfoPackages(packageName, newShortcuts); - final int size = newShortcuts.size(); + final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); + verifyShortcutInfoPackages(packageName, newShortcuts); + final int size = newShortcuts.size(); - final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission( - injectBinderCallingPid(), injectBinderCallingUid()); + final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission( + injectBinderCallingPid(), injectBinderCallingUid()); - List<ShortcutInfo> changedShortcuts = null; - List<ShortcutInfo> removedShortcuts = null; + List<ShortcutInfo> changedShortcuts = null; + List<ShortcutInfo> removedShortcuts = null; - synchronized (mLock) { - throwIfUserLockedL(userId); + synchronized (mLock) { + throwIfUserLockedL(userId); - final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); + final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, + userId); - ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); - ps.ensureNoBitmapIconIfShortcutIsLongLived(newShortcuts); + ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); + ps.ensureNoBitmapIconIfShortcutIsLongLived(newShortcuts); - fillInDefaultActivity(newShortcuts); + fillInDefaultActivity(newShortcuts); - ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_SET); + ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_SET); - // Throttling. - if (!ps.tryApiCall(unlimited)) { - callback.complete(false); - } + // Throttling. + if (!ps.tryApiCall(unlimited)) { + callback.complete(false); + return; + } - // Initialize the implicit ranks for ShortcutPackage.adjustRanks(). - ps.clearAllImplicitRanks(); - assignImplicitRanks(newShortcuts); + // Initialize the implicit ranks for ShortcutPackage.adjustRanks(). + ps.clearAllImplicitRanks(); + assignImplicitRanks(newShortcuts); - for (int i = 0; i < size; i++) { - fixUpIncomingShortcutInfo(newShortcuts.get(i), /* forUpdate= */ false); - } + for (int i = 0; i < size; i++) { + fixUpIncomingShortcutInfo(newShortcuts.get(i), /* forUpdate= */ false); + } - ArrayList<ShortcutInfo> cachedOrPinned = new ArrayList<>(); - ps.findAll(cachedOrPinned, (ShortcutInfo si) -> si.isVisibleToPublisher() - && si.isDynamic() && (si.isCached() || si.isPinned()), - ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO); + ArrayList<ShortcutInfo> cachedOrPinned = new ArrayList<>(); + ps.findAll(cachedOrPinned, (ShortcutInfo si) -> si.isVisibleToPublisher() + && si.isDynamic() && (si.isCached() || si.isPinned()), + ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO); - // First, remove all un-pinned and non-cached; dynamic shortcuts - removedShortcuts = ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true); + // First, remove all un-pinned and non-cached; dynamic shortcuts + removedShortcuts = ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true); - // Then, add/update all. We need to make sure to take over "pinned" flag. - for (int i = 0; i < size; i++) { - final ShortcutInfo newShortcut = newShortcuts.get(i); - ps.addOrReplaceDynamicShortcut(newShortcut); - } + // Then, add/update all. We need to make sure to take over "pinned" flag. + for (int i = 0; i < size; i++) { + final ShortcutInfo newShortcut = newShortcuts.get(i); + ps.addOrReplaceDynamicShortcut(newShortcut); + } - // Lastly, adjust the ranks. - ps.adjustRanks(); + // Lastly, adjust the ranks. + ps.adjustRanks(); - changedShortcuts = prepareChangedShortcuts( - cachedOrPinned, newShortcuts, removedShortcuts, ps); - } + changedShortcuts = prepareChangedShortcuts( + cachedOrPinned, newShortcuts, removedShortcuts, ps); + } - packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts); + packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts); - verifyStates(); + verifyStates(); - callback.complete(true); + callback.complete(true); + } catch (Exception e) { + callback.completeExceptionally(e); + } } @Override public void updateShortcuts(String packageName, ParceledListSlice shortcutInfoList, @UserIdInt int userId, AndroidFuture callback) { - verifyCaller(packageName, userId); + try { + verifyCaller(packageName, userId); - final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); - verifyShortcutInfoPackages(packageName, newShortcuts); - final int size = newShortcuts.size(); + final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); + verifyShortcutInfoPackages(packageName, newShortcuts); + final int size = newShortcuts.size(); - final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission( - injectBinderCallingPid(), injectBinderCallingUid()); + final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission( + injectBinderCallingPid(), injectBinderCallingUid()); - final List<ShortcutInfo> changedShortcuts = new ArrayList<>(1); + final List<ShortcutInfo> changedShortcuts = new ArrayList<>(1); - synchronized (mLock) { - throwIfUserLockedL(userId); + synchronized (mLock) { + throwIfUserLockedL(userId); - final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); + final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, + userId); - ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); - ps.ensureNoBitmapIconIfShortcutIsLongLived(newShortcuts); + ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); + ps.ensureNoBitmapIconIfShortcutIsLongLived(newShortcuts); - // For update, don't fill in the default activity. Having null activity means - // "don't update the activity" here. + // For update, don't fill in the default activity. Having null activity means + // "don't update the activity" here. - ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_UPDATE); + ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_UPDATE); - // Throttling. - if (!ps.tryApiCall(unlimited)) { - callback.complete(false); - return; - } + // Throttling. + if (!ps.tryApiCall(unlimited)) { + callback.complete(false); + return; + } - // Initialize the implicit ranks for ShortcutPackage.adjustRanks(). - ps.clearAllImplicitRanks(); - assignImplicitRanks(newShortcuts); + // Initialize the implicit ranks for ShortcutPackage.adjustRanks(). + ps.clearAllImplicitRanks(); + assignImplicitRanks(newShortcuts); - for (int i = 0; i < size; i++) { - final ShortcutInfo source = newShortcuts.get(i); - fixUpIncomingShortcutInfo(source, /* forUpdate= */ true); + for (int i = 0; i < size; i++) { + final ShortcutInfo source = newShortcuts.get(i); + fixUpIncomingShortcutInfo(source, /* forUpdate= */ true); - ps.mutateShortcut(source.getId(), null, target -> { - // Invisible shortcuts can't be updated. - if (target == null || !target.isVisibleToPublisher()) { - return; - } + ps.mutateShortcut(source.getId(), null, target -> { + // Invisible shortcuts can't be updated. + if (target == null || !target.isVisibleToPublisher()) { + return; + } - if (target.isEnabled() != source.isEnabled()) { - Slog.w(TAG, - "ShortcutInfo.enabled cannot be changed with updateShortcuts()"); - } + if (target.isEnabled() != source.isEnabled()) { + Slog.w(TAG, "ShortcutInfo.enabled cannot be changed with" + + " updateShortcuts()"); + } - if (target.isLongLived() != source.isLongLived()) { - Slog.w(TAG, - "ShortcutInfo.longLived cannot be changed with updateShortcuts()"); - } + if (target.isLongLived() != source.isLongLived()) { + Slog.w(TAG, + "ShortcutInfo.longLived cannot be changed with" + + " updateShortcuts()"); + } - // When updating the rank, we need to insert between existing ranks, so set - // this setRankChanged, and also copy the implicit rank fo adjustRanks(). - if (source.hasRank()) { - target.setRankChanged(); - target.setImplicitRank(source.getImplicitRank()); - } + // When updating the rank, we need to insert between existing ranks, so set + // this setRankChanged, and also copy the implicit rank fo adjustRanks(). + if (source.hasRank()) { + target.setRankChanged(); + target.setImplicitRank(source.getImplicitRank()); + } - final boolean replacingIcon = (source.getIcon() != null); - if (replacingIcon) { - removeIconLocked(target); - } + final boolean replacingIcon = (source.getIcon() != null); + if (replacingIcon) { + removeIconLocked(target); + } - // Note copyNonNullFieldsFrom() does the "updatable with?" check too. - target.copyNonNullFieldsFrom(source); - target.setTimestamp(injectCurrentTimeMillis()); + // Note copyNonNullFieldsFrom() does the "updatable with?" check too. + target.copyNonNullFieldsFrom(source); + target.setTimestamp(injectCurrentTimeMillis()); - if (replacingIcon) { - saveIconAndFixUpShortcutLocked(target); - } + if (replacingIcon) { + saveIconAndFixUpShortcutLocked(target); + } - // When we're updating any resource related fields, re-extract the res names and - // the values. - if (replacingIcon || source.hasStringResources()) { - fixUpShortcutResourceNamesAndValues(target); - } + // When we're updating any resource related fields, re-extract the res + // names and the values. + if (replacingIcon || source.hasStringResources()) { + fixUpShortcutResourceNamesAndValues(target); + } - changedShortcuts.add(target); - }); - } + changedShortcuts.add(target); + }); + } - // Lastly, adjust the ranks. - ps.adjustRanks(); - } - packageShortcutsChanged(packageName, userId, - changedShortcuts.isEmpty() ? null : changedShortcuts, null); + // Lastly, adjust the ranks. + ps.adjustRanks(); + } + packageShortcutsChanged(packageName, userId, + changedShortcuts.isEmpty() ? null : changedShortcuts, null); - verifyStates(); + verifyStates(); - callback.complete(true); + callback.complete(true); + } catch (Exception e) { + callback.completeExceptionally(e); + } } @Override public void addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, @UserIdInt int userId, AndroidFuture callback) { - verifyCaller(packageName, userId); + try { + verifyCaller(packageName, userId); - final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); - verifyShortcutInfoPackages(packageName, newShortcuts); - final int size = newShortcuts.size(); + final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); + verifyShortcutInfoPackages(packageName, newShortcuts); + final int size = newShortcuts.size(); - final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission( - injectBinderCallingPid(), injectBinderCallingUid()); + final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission( + injectBinderCallingPid(), injectBinderCallingUid()); - List<ShortcutInfo> changedShortcuts = null; + List<ShortcutInfo> changedShortcuts = null; - synchronized (mLock) { - throwIfUserLockedL(userId); + synchronized (mLock) { + throwIfUserLockedL(userId); - final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); + final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, + userId); - ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); - ps.ensureNoBitmapIconIfShortcutIsLongLived(newShortcuts); + ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); + ps.ensureNoBitmapIconIfShortcutIsLongLived(newShortcuts); - fillInDefaultActivity(newShortcuts); + fillInDefaultActivity(newShortcuts); - ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_ADD); + ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_ADD); - // Initialize the implicit ranks for ShortcutPackage.adjustRanks(). - ps.clearAllImplicitRanks(); - assignImplicitRanks(newShortcuts); + // Initialize the implicit ranks for ShortcutPackage.adjustRanks(). + ps.clearAllImplicitRanks(); + assignImplicitRanks(newShortcuts); - // Throttling. - if (!ps.tryApiCall(unlimited)) { - callback.complete(false); - return; - } - for (int i = 0; i < size; i++) { - final ShortcutInfo newShortcut = newShortcuts.get(i); + // Throttling. + if (!ps.tryApiCall(unlimited)) { + callback.complete(false); + return; + } + for (int i = 0; i < size; i++) { + final ShortcutInfo newShortcut = newShortcuts.get(i); - // Validate the shortcut. - fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false); + // Validate the shortcut. + fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false); - // When ranks are changing, we need to insert between ranks, so set the - // "rank changed" flag. - newShortcut.setRankChanged(); + // When ranks are changing, we need to insert between ranks, so set the + // "rank changed" flag. + newShortcut.setRankChanged(); - // Add it. - ps.addOrReplaceDynamicShortcut(newShortcut); + // Add it. + ps.addOrReplaceDynamicShortcut(newShortcut); - if (changedShortcuts == null) { - changedShortcuts = new ArrayList<>(1); + if (changedShortcuts == null) { + changedShortcuts = new ArrayList<>(1); + } + changedShortcuts.add(newShortcut); } - changedShortcuts.add(newShortcut); - } - // Lastly, adjust the ranks. - ps.adjustRanks(); - } - packageShortcutsChanged(packageName, userId, changedShortcuts, null); + // Lastly, adjust the ranks. + ps.adjustRanks(); + } + packageShortcutsChanged(packageName, userId, changedShortcuts, null); - verifyStates(); + verifyStates(); - callback.complete(true); + callback.complete(true); + } catch (Exception e) { + callback.completeExceptionally(e); + } } @Override @@ -2180,31 +2197,40 @@ public class ShortcutService extends IShortcutService.Stub { @Override public void requestPinShortcut(String packageName, ShortcutInfo shortcut, IntentSender resultIntent, int userId, AndroidFuture callback) { - Objects.requireNonNull(shortcut); - Objects.requireNonNull(callback); - Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled"); - callback.complete(requestPinItem(packageName, userId, shortcut, null, null, resultIntent)); + try { + Objects.requireNonNull(shortcut); + Objects.requireNonNull(callback); + Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled"); + callback.complete( + requestPinItem(packageName, userId, shortcut, null, null, resultIntent)); + } catch (Exception e) { + callback.completeExceptionally(e); + } } @Override public void createShortcutResultIntent(String packageName, ShortcutInfo shortcut, int userId, AndroidFuture callback) throws RemoteException { - Objects.requireNonNull(shortcut); - Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled"); - verifyCaller(packageName, userId); - verifyShortcutInfoPackage(packageName, shortcut); + try { + Objects.requireNonNull(shortcut); + Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled"); + verifyCaller(packageName, userId); + verifyShortcutInfoPackage(packageName, shortcut); - final Intent ret; - synchronized (mLock) { - throwIfUserLockedL(userId); + final Intent ret; + synchronized (mLock) { + throwIfUserLockedL(userId); - // Send request to the launcher, if supported. - ret = mShortcutRequestPinProcessor.createShortcutResultIntent(shortcut, userId); - } + // Send request to the launcher, if supported. + ret = mShortcutRequestPinProcessor.createShortcutResultIntent(shortcut, userId); + } - verifyStates(); - callback.complete(ret); + verifyStates(); + callback.complete(ret); + } catch (Exception e) { + callback.completeExceptionally(e); + } } /** @@ -2464,47 +2490,57 @@ public class ShortcutService extends IShortcutService.Stub { public void getShortcuts(String packageName, @ShortcutManager.ShortcutMatchFlags int matchFlags, @UserIdInt int userId, AndroidFuture<ParceledListSlice<ShortcutInfo>> callback) { - verifyCaller(packageName, userId); - - synchronized (mLock) { - throwIfUserLockedL(userId); - - final boolean matchDynamic = (matchFlags & ShortcutManager.FLAG_MATCH_DYNAMIC) != 0; - final boolean matchPinned = (matchFlags & ShortcutManager.FLAG_MATCH_PINNED) != 0; - final boolean matchManifest = (matchFlags & ShortcutManager.FLAG_MATCH_MANIFEST) != 0; - final boolean matchCached = (matchFlags & ShortcutManager.FLAG_MATCH_CACHED) != 0; + try { + verifyCaller(packageName, userId); - final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0) - | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0) - | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0) - | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0); + synchronized (mLock) { + throwIfUserLockedL(userId); - callback.complete(getShortcutsWithQueryLocked( - packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, - (ShortcutInfo si) -> - si.isVisibleToPublisher() && (si.getFlags() & shortcutFlags) != 0)); + final boolean matchDynamic = (matchFlags & ShortcutManager.FLAG_MATCH_DYNAMIC) != 0; + final boolean matchPinned = (matchFlags & ShortcutManager.FLAG_MATCH_PINNED) != 0; + final boolean matchManifest = + (matchFlags & ShortcutManager.FLAG_MATCH_MANIFEST) != 0; + final boolean matchCached = (matchFlags & ShortcutManager.FLAG_MATCH_CACHED) != 0; + + final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0) + | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0) + | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0) + | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0); + + callback.complete(getShortcutsWithQueryLocked( + packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, + (ShortcutInfo si) -> + si.isVisibleToPublisher() && (si.getFlags() & shortcutFlags) != 0)); + } + } catch (Exception e) { + callback.completeExceptionally(e); } } @Override public void getShareTargets(String packageName, IntentFilter filter, @UserIdInt int userId, AndroidFuture<ParceledListSlice> callback) { - Preconditions.checkStringNotEmpty(packageName, "packageName"); - Objects.requireNonNull(filter, "intentFilter"); + try { + Preconditions.checkStringNotEmpty(packageName, "packageName"); + Objects.requireNonNull(filter, "intentFilter"); - verifyCaller(packageName, userId); - enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS, - "getShareTargets"); + verifyCaller(packageName, userId); + enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS, + "getShareTargets"); - synchronized (mLock) { - throwIfUserLockedL(userId); + synchronized (mLock) { + throwIfUserLockedL(userId); - final List<ShortcutManager.ShareShortcutInfo> shortcutInfoList = new ArrayList<>(); + final List<ShortcutManager.ShareShortcutInfo> shortcutInfoList = new ArrayList<>(); - final ShortcutUser user = getUserShortcutsLocked(userId); - user.forAllPackages(p -> shortcutInfoList.addAll(p.getMatchingShareTargets(filter))); + final ShortcutUser user = getUserShortcutsLocked(userId); + user.forAllPackages( + p -> shortcutInfoList.addAll(p.getMatchingShareTargets(filter))); - callback.complete(new ParceledListSlice<>(shortcutInfoList)); + callback.complete(new ParceledListSlice<>(shortcutInfoList)); + } + } catch (Exception e) { + callback.completeExceptionally(e); } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 047e3b362b7a..ffea6a743a42 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -345,6 +345,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { */ private final Object mLock = new Object(); + /** List of {@link ScreenOnListener}s which do not belong to the default display. */ + private final SparseArray<ScreenOnListener> mScreenOnListeners = new SparseArray<>(); + Context mContext; IWindowManager mWindowManager; WindowManagerFuncs mWindowManagerFuncs; @@ -434,8 +437,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { volatile boolean mBeganFromNonInteractive; volatile boolean mEndCallKeyHandled; volatile boolean mCameraGestureTriggeredDuringGoingToSleep; - volatile boolean mGoingToSleep; - volatile boolean mRequestedOrGoingToSleep; + + /** + * {@code true} if the device is entering a low-power state; {@code false otherwise}. + * + * <p>This differs from {@link #mRequestedOrSleepingDefaultDisplay} which tracks the power state + * of the {@link #mDefaultDisplay default display} versus the power state of the entire device. + */ + volatile boolean mDeviceGoingToSleep; + + /** + * {@code true} if the {@link #mDefaultDisplay default display} is entering or was requested to + * enter a low-power state; {@code false otherwise}. + * + * <p>This differs from {@link #mDeviceGoingToSleep} which tracks the power state of the entire + * device versus the power state of the {@link #mDefaultDisplay default display}. + */ + // TODO(b/178103325): Track sleep/requested sleep for every display. + volatile boolean mRequestedOrSleepingDefaultDisplay; + volatile boolean mRecentsVisible; volatile boolean mNavBarVirtualKeyHapticFeedbackEnabled = true; volatile boolean mPictureInPictureVisible; @@ -917,13 +937,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { case SHORT_PRESS_POWER_NOTHING: break; case SHORT_PRESS_POWER_GO_TO_SLEEP: - goToSleepFromPowerButton(eventTime, 0); + sleepDefaultDisplayFromPowerButton(eventTime, 0); break; case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP: - goToSleepFromPowerButton(eventTime, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); + sleepDefaultDisplayFromPowerButton(eventTime, + PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); break; case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME: - if (goToSleepFromPowerButton(eventTime, + if (sleepDefaultDisplayFromPowerButton(eventTime, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE)) { launchHomeFromHotKey(DEFAULT_DISPLAY); } @@ -951,11 +972,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** - * Sends the device to sleep as a result of a power button press. + * Sends the default display to sleep as a result of a power button press. * - * @return True if the was device was sent to sleep, false if sleep was suppressed. + * @return {@code true} if the device was sent to sleep, {@code false} if the device did not + * sleep. */ - private boolean goToSleepFromPowerButton(long eventTime, int flags) { + private boolean sleepDefaultDisplayFromPowerButton(long eventTime, int flags) { // Before we actually go to sleep, we check the last wakeup reason. // If the device very recently woke up from a gesture (like user lifting their device) // then ignore the sleep instruction. This is because users have developed @@ -975,12 +997,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags); + sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags); return true; } - private void goToSleep(long eventTime, int reason, int flags) { - mRequestedOrGoingToSleep = true; + private void sleepDefaultDisplay(long eventTime, int reason, int flags) { + mRequestedOrSleepingDefaultDisplay = true; mPowerManager.goToSleep(eventTime, reason, flags); } @@ -1017,7 +1039,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Global.THEATER_MODE_ON, 1); if (mGoToSleepOnButtonPressTheaterMode && interactive) { - goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); + sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, + 0); } } break; @@ -1126,7 +1149,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case SHORT_PRESS_SLEEP_GO_TO_SLEEP: case SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME: Slog.i(TAG, "sleepRelease() calling goToSleep(GO_TO_SLEEP_REASON_SLEEP_BUTTON)"); - goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0); + sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0); break; } } @@ -3511,7 +3534,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if ((mEndcallBehavior & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) { - goToSleep(event.getEventTime(), + sleepDefaultDisplay(event.getEventTime(), PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); isWakeKey = false; } @@ -3538,10 +3561,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Any activity on the power button stops the accessibility shortcut result &= ~ACTION_PASS_TO_USER; isWakeKey = false; // wake-up will be handled separately + final boolean isDefaultDisplayOn = Display.isOnState(mDefaultDisplay.getState()); + final boolean interactiveAndOn = interactive && isDefaultDisplayOn; if (down) { - interceptPowerKeyDown(event, interactive); + interceptPowerKeyDown(event, interactiveAndOn); } else { - interceptPowerKeyUp(event, interactive, canceled); + interceptPowerKeyUp(event, interactiveAndOn, canceled); } break; } @@ -3746,7 +3771,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final MutableBoolean outLaunched = new MutableBoolean(false); final boolean gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive, outLaunched); - if (outLaunched.value && mRequestedOrGoingToSleep) { + if (outLaunched.value && mRequestedOrSleepingDefaultDisplay) { mCameraGestureTriggeredDuringGoingToSleep = true; } return gesturedServiceIntercepted; @@ -4088,8 +4113,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { pmSleepReason)) + ")"); } - mGoingToSleep = true; - mRequestedOrGoingToSleep = true; + mDeviceGoingToSleep = true; + mRequestedOrSleepingDefaultDisplay = true; if (mKeyguardDelegate != null) { mKeyguardDelegate.onStartedGoingToSleep(pmSleepReason); @@ -4108,8 +4133,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000); - mGoingToSleep = false; - mRequestedOrGoingToSleep = false; + mDeviceGoingToSleep = false; + mRequestedOrSleepingDefaultDisplay = false; mDefaultDisplayPolicy.setAwake(false); // We must get this work done here because the power manager will drop @@ -4253,21 +4278,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Called on the DisplayManager's DisplayPowerController thread. @Override public void screenTurnedOff(int displayId) { - if (displayId != DEFAULT_DISPLAY) { - return; - } - - if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off..."); + if (DEBUG_WAKEUP) Slog.i(TAG, "Display" + displayId + " turned off..."); - updateScreenOffSleepToken(true); - mDefaultDisplayPolicy.screenTurnedOff(); - synchronized (mLock) { - if (mKeyguardDelegate != null) { - mKeyguardDelegate.onScreenTurnedOff(); + if (displayId == DEFAULT_DISPLAY) { + updateScreenOffSleepToken(true); + mRequestedOrSleepingDefaultDisplay = false; + mDefaultDisplayPolicy.screenTurnedOff(); + synchronized (mLock) { + if (mKeyguardDelegate != null) { + mKeyguardDelegate.onScreenTurnedOff(); + } + } + mDefaultDisplayRotation.updateOrientationListener(); + reportScreenStateToVrManager(false); + if (mCameraGestureTriggeredDuringGoingToSleep) { + wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromPowerKey, + PowerManager.WAKE_REASON_CAMERA_LAUNCH, + "com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK"); } } - mDefaultDisplayRotation.updateOrientationListener(); - reportScreenStateToVrManager(false); } private long getKeyguardDrawnTimeout() { @@ -4280,27 +4309,28 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Called on the DisplayManager's DisplayPowerController thread. @Override public void screenTurningOn(int displayId, final ScreenOnListener screenOnListener) { - if (displayId != DEFAULT_DISPLAY) { - return; - } - - if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on..."); + if (DEBUG_WAKEUP) Slog.i(TAG, "Display " + displayId + " turning on..."); - Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */); - updateScreenOffSleepToken(false); - mDefaultDisplayPolicy.screenTurnedOn(screenOnListener); + if (displayId == DEFAULT_DISPLAY) { + Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", + 0 /* cookie */); + updateScreenOffSleepToken(false); + mDefaultDisplayPolicy.screenTurnedOn(screenOnListener); - synchronized (mLock) { - if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) { - mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT); - mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, - getKeyguardDrawnTimeout()); - mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback); - } else { - if (DEBUG_WAKEUP) Slog.d(TAG, - "null mKeyguardDelegate: setting mKeyguardDrawComplete."); - mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE); + synchronized (mLock) { + if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) { + mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT); + mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, + getKeyguardDrawnTimeout()); + mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback); + } else { + if (DEBUG_WAKEUP) Slog.d(TAG, + "null mKeyguardDelegate: setting mKeyguardDrawComplete."); + mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE); + } } + } else { + mScreenOnListeners.put(displayId, screenOnListener); } } @@ -4321,11 +4351,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void screenTurningOff(int displayId, ScreenOffListener screenOffListener) { + mWindowManagerFuncs.screenTurningOff(displayId, screenOffListener); if (displayId != DEFAULT_DISPLAY) { return; } - mWindowManagerFuncs.screenTurningOff(screenOffListener); + mRequestedOrSleepingDefaultDisplay = true; synchronized (mLock) { if (mKeyguardDelegate != null) { mKeyguardDelegate.onScreenTurningOff(); @@ -4380,6 +4411,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { listener.onScreenOn(); } + for (int i = mScreenOnListeners.size() - 1; i >= 0; i--) { + final ScreenOnListener screenOnListener = mScreenOnListeners.valueAt(i); + if (screenOnListener != null) { + screenOnListener.onScreenOn(); + } + } + mScreenOnListeners.clear(); + if (enableScreen) { try { mWindowManager.enableScreenIfNeeded(); @@ -4410,7 +4449,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public boolean okToAnimate() { - return mDefaultDisplayPolicy.isAwake() && !mGoingToSleep; + return mDefaultDisplayPolicy.isAwake() && !mDeviceGoingToSleep; } /** {@inheritDoc} */ @@ -4777,7 +4816,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerFuncs.lockDeviceNow(); break; case LID_BEHAVIOR_SLEEP: - goToSleep(SystemClock.uptimeMillis(), + sleepDefaultDisplay(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); break; diff --git a/services/core/java/com/android/server/policy/SplashScreenSurface.java b/services/core/java/com/android/server/policy/SplashScreenSurface.java index b9202c334fec..72933a0ad309 100644 --- a/services/core/java/com/android/server/policy/SplashScreenSurface.java +++ b/services/core/java/com/android/server/policy/SplashScreenSurface.java @@ -45,7 +45,7 @@ class SplashScreenSurface implements StartingSurface { } @Override - public void remove() { + public void remove(boolean animate) { if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + mAppToken + ": " + this + " Callers=" + Debug.getCallers(4)); diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index b5a9acacec83..0735977be72a 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -238,8 +238,9 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { /** * Removes the starting window surface. Do not hold the window manager lock when calling * this method! + * @param animate Whether need to play the default exit animation for starting window. */ - void remove(); + void remove(boolean animate); } /** @@ -303,9 +304,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { /** * Notifies the window manager that screen is being turned off. * + * @param displayId the ID of the display which is turning off * @param listener callback to call when display can be turned off */ - void screenTurningOff(ScreenOffListener listener); + void screenTurningOff(int displayId, ScreenOffListener listener); /** * Convert the lid state to a human readable format. diff --git a/services/core/java/com/android/server/power/FaceDownDetector.java b/services/core/java/com/android/server/power/FaceDownDetector.java index 2442079bec8b..676181dcfb67 100644 --- a/services/core/java/com/android/server/power/FaceDownDetector.java +++ b/services/core/java/com/android/server/power/FaceDownDetector.java @@ -30,6 +30,7 @@ import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Handler; import android.os.Looper; +import android.os.PowerManager; import android.os.SystemClock; import android.provider.DeviceConfig; import android.util.Slog; @@ -66,7 +67,7 @@ public class FaceDownDetector implements SensorEventListener { private static final float MOVING_AVERAGE_WEIGHT = 0.5f; /** DeviceConfig flag name, if {@code true}, enables Face Down features. */ - private static final String KEY_FEATURE_ENABLED = "enable_flip_to_screen_off"; + static final String KEY_FEATURE_ENABLED = "enable_flip_to_screen_off"; /** Default value in absence of {@link DeviceConfig} override. */ private static final boolean DEFAULT_FEATURE_ENABLED = true; @@ -139,6 +140,7 @@ public class FaceDownDetector implements SensorEventListener { new ExponentialMovingAverage(MOVING_AVERAGE_WEIGHT); private boolean mFaceDown = false; + private boolean mInteractive = false; private boolean mActive = false; private float mPrevAcceleration = 0; @@ -149,62 +151,64 @@ public class FaceDownDetector implements SensorEventListener { private final Handler mHandler; private final Runnable mUserActivityRunnable; + private final BroadcastReceiver mScreenReceiver; + + private Context mContext; public FaceDownDetector(@NonNull Consumer<Boolean> onFlip) { mOnFlip = Objects.requireNonNull(onFlip); mHandler = new Handler(Looper.getMainLooper()); + mScreenReceiver = new ScreenStateReceiver(); mUserActivityRunnable = () -> { if (mFaceDown) { exitFaceDown(USER_INTERACTION, SystemClock.uptimeMillis() - mLastFlipTime); - checkAndUpdateActiveState(false); + updateActiveState(); } }; } /** Initializes the FaceDownDetector and all necessary listeners. */ public void systemReady(Context context) { + mContext = context; mSensorManager = context.getSystemService(SensorManager.class); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); readValuesFromDeviceConfig(); - checkAndUpdateActiveState(true); DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_ATTENTION_MANAGER_SERVICE, ActivityThread.currentApplication().getMainExecutor(), (properties) -> onDeviceConfigChange(properties.getKeyset())); + updateActiveState(); + } + + private void registerScreenReceiver(Context context) { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - context.registerReceiver(new ScreenStateReceiver(), intentFilter); + context.registerReceiver(mScreenReceiver, intentFilter); } /** * Sets the active state of the detector. If false, we will not process accelerometer changes. */ - private void checkAndUpdateActiveState(boolean active) { - if (mIsEnabled && mActive != active) { - final long currentTime = SystemClock.uptimeMillis(); - // Don't make active if there was recently a user interaction while face down. - if (active && mPreviousResultType == USER_INTERACTION - && currentTime - mPreviousResultTime < mUserInteractionBackoffMillis) { - return; - } - if (DEBUG) Slog.d(TAG, "Update active - " + active); - mActive = active; - if (!active) { - if (mFaceDown && mPreviousResultTime != USER_INTERACTION) { - mPreviousResultType = SCREEN_OFF_RESULT; - mPreviousResultTime = currentTime; + private void updateActiveState() { + final long currentTime = SystemClock.uptimeMillis(); + final boolean sawRecentInteraction = mPreviousResultType == USER_INTERACTION + && currentTime - mPreviousResultTime < mUserInteractionBackoffMillis; + final boolean shouldBeActive = mInteractive && mIsEnabled && !sawRecentInteraction; + if (mActive != shouldBeActive) { + if (shouldBeActive) { + mSensorManager.registerListener( + this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); + if (mPreviousResultType == SCREEN_OFF_RESULT) { + logScreenOff(); } + } else { mSensorManager.unregisterListener(this); mFaceDown = false; mOnFlip.accept(false); - } else { - if (mPreviousResultType == SCREEN_OFF_RESULT) { - logScreenOff(); - } - mSensorManager.registerListener( - this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); } + mActive = shouldBeActive; + if (DEBUG) Slog.d(TAG, "Update active - " + shouldBeActive); } } @@ -287,8 +291,10 @@ public class FaceDownDetector implements SensorEventListener { * The user interacted with the screen while face down, indicated the phone is in use. * We log this event and temporarily make this detector inactive. */ - public void userActivity() { - mHandler.post(mUserActivityRunnable); + public void userActivity(int event) { + if (event != PowerManager.USER_ACTIVITY_EVENT_FACE_DOWN) { + mHandler.post(mUserActivityRunnable); + } } private void exitFaceDown(int resultType, long millisSinceFlip) { @@ -389,6 +395,7 @@ public class FaceDownDetector implements SensorEventListener { case KEY_TIME_THRESHOLD_MILLIS: case KEY_FEATURE_ENABLED: readValuesFromDeviceConfig(); + updateActiveState(); return; default: Slog.i(TAG, "Ignoring change on " + key); @@ -401,8 +408,18 @@ public class FaceDownDetector implements SensorEventListener { mZAccelerationThreshold = getZAccelerationThreshold(); mZAccelerationThresholdLenient = mZAccelerationThreshold + 1.0f; mTimeThreshold = getTimeThreshold(); - mIsEnabled = isEnabled(); mUserInteractionBackoffMillis = getUserInteractionBackoffMillis(); + final boolean oldEnabled = mIsEnabled; + mIsEnabled = isEnabled(); + if (oldEnabled != mIsEnabled) { + if (!mIsEnabled) { + mContext.unregisterReceiver(mScreenReceiver); + mInteractive = false; + } else { + registerScreenReceiver(mContext); + mInteractive = mContext.getSystemService(PowerManager.class).isInteractive(); + } + } Slog.i(TAG, "readValuesFromDeviceConfig():" + "\nmAccelerationThreshold=" + mAccelerationThreshold @@ -423,9 +440,11 @@ public class FaceDownDetector implements SensorEventListener { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { - checkAndUpdateActiveState(false); + mInteractive = false; + updateActiveState(); } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) { - checkAndUpdateActiveState(true); + mInteractive = true; + updateActiveState(); } } } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index f49e2f1631b9..7555a7f2920b 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -549,6 +549,7 @@ public class Notifier { if (!mUserActivityPending) { mUserActivityPending = true; Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY); + msg.arg1 = event; msg.setAsynchronous(true); mHandler.sendMessage(msg); } @@ -647,7 +648,7 @@ public class Notifier { mSuspendBlocker.release(); } - private void sendUserActivity() { + private void sendUserActivity(int event) { synchronized (mLock) { if (!mUserActivityPending) { return; @@ -657,7 +658,7 @@ public class Notifier { TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); tm.notifyUserActivity(); mPolicy.userActivity(); - mFaceDownDetector.userActivity(); + mFaceDownDetector.userActivity(event); } void postEnhancedDischargePredictionBroadcast(long delayMs) { @@ -833,7 +834,7 @@ public class Notifier { public void handleMessage(Message msg) { switch (msg.what) { case MSG_USER_ACTIVITY: - sendUserActivity(); + sendUserActivity(msg.arg1); break; case MSG_BROADCAST: sendNextBroadcast(); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 29adde37ab3b..d2a4cd604c01 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -180,8 +180,6 @@ public final class PowerManagerService extends SystemService private static final int DIRTY_VR_MODE_CHANGED = 1 << 13; // Dirty bit: attentive timer may have timed out private static final int DIRTY_ATTENTIVE = 1 << 14; - // Dirty bit: phone flipped to face down - private static final int DIRTY_FACE_DOWN = 1 << 15; // Dirty bit: display group power state has changed private static final int DIRTY_DISPLAY_GROUP_POWER_UPDATED = 1 << 16; @@ -1069,8 +1067,9 @@ public final class PowerManagerService extends SystemService final long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout, -1L); millisUntilNormalTimeout = mLastUserActivityTime + screenOffTimeout - mClock.uptimeMillis(); - mDirty |= DIRTY_FACE_DOWN; - updatePowerStateLocked(); + userActivityInternal(mClock.uptimeMillis(), + PowerManager.USER_ACTIVITY_EVENT_FACE_DOWN, /* flags= */0, + Process.SYSTEM_UID); } } if (isFaceDown) { diff --git a/services/core/java/com/android/server/power/PreRebootLogger.java b/services/core/java/com/android/server/power/PreRebootLogger.java index 2e4b054b829c..c9e81ed7a796 100644 --- a/services/core/java/com/android/server/power/PreRebootLogger.java +++ b/services/core/java/com/android/server/power/PreRebootLogger.java @@ -19,7 +19,6 @@ package com.android.server.power; import android.annotation.DurationMillisLong; import android.annotation.NonNull; import android.content.Context; -import android.os.Binder; import android.os.Environment; import android.os.IBinder; import android.os.ParcelFileDescriptor; @@ -147,7 +146,6 @@ final class PreRebootLogger { return; } - final long token = Binder.clearCallingIdentity(); try { final File dumpFile = new File(dumpDir, serviceName); final ParcelFileDescriptor fd = ParcelFileDescriptor.open(dumpFile, @@ -156,8 +154,6 @@ final class PreRebootLogger { binder.dump(fd.getFileDescriptor(), ArrayUtils.emptyArray(String.class)); } catch (FileNotFoundException | RemoteException e) { Slog.e(TAG, String.format("Failed to dump %s service before reboot", serviceName), e); - } finally { - Binder.restoreCallingIdentity(token); } } } diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index 3a08ddc6c405..fc62f5be801c 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -24,6 +24,7 @@ import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.content.rollback.PackageRollbackInfo.RestoreInfo; import android.content.rollback.RollbackInfo; +import android.os.SystemProperties; import android.os.UserHandle; import android.system.ErrnoException; import android.system.Os; @@ -227,6 +228,15 @@ class RollbackStore { packageSessionIds, extensionVersions); } + private static boolean isLinkPossible(File oldFile, File newFile) { + try { + return Os.stat(oldFile.getAbsolutePath()).st_dev + == Os.stat(newFile.getAbsolutePath()).st_dev; + } catch (ErrnoException ignore) { + return false; + } + } + /** * Creates a backup copy of an apk or apex for a package. * For packages containing splits, this method should be called for each @@ -239,16 +249,29 @@ class RollbackStore { targetDir.mkdirs(); File targetFile = new File(targetDir, sourceFile.getName()); - try { - // Create a hard link to avoid copy - // TODO(b/168562373) - // Linking between non-encrypted and encrypted is not supported and we have - // encrypted /data/rollback and non-encrypted /data/apex/active. For now this works - // because we happen to store encrypted files under /data/apex/active which is no - // longer the case when compressed apex rolls out. We have to handle this case in - // order not to fall back to copy. - Os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath()); - } catch (ErrnoException ignore) { + boolean fallbackToCopy = !isLinkPossible(sourceFile, targetFile); + if (!fallbackToCopy) { + try { + // Create a hard link to avoid copy + // TODO(b/168562373) + // Linking between non-encrypted and encrypted is not supported and we have + // encrypted /data/rollback and non-encrypted /data/apex/active. For now this works + // because we happen to store encrypted files under /data/apex/active which is no + // longer the case when compressed apex rolls out. We have to handle this case in + // order not to fall back to copy. + Os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath()); + } catch (ErrnoException e) { + boolean isRollbackTest = + SystemProperties.getBoolean("persist.rollback.is_test", false); + if (isRollbackTest) { + throw new IOException(e); + } else { + fallbackToCopy = true; + } + } + } + + if (fallbackToCopy) { // Fall back to copy if hardlink can't be created Files.copy(sourceFile.toPath(), targetFile.toPath()); } diff --git a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java index cfb4c27820fa..189f47f7f1da 100644 --- a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java +++ b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java @@ -77,9 +77,7 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol @GuardedBy("mLock") public void resolveRotationLocked(RotationRequest request) { - final RotationResolutionRequest remoteRequest = new RotationResolutionRequest( - request.mProposedRotation, request.mCurrentRotation, request.mPackageName, - request.mTimeoutMillis); + final RotationResolutionRequest remoteRequest = request.mRemoteRequest; post(service -> service.resolveRotation(request.mIRotationResolverCallback, remoteRequest)); // schedule a timeout. @@ -91,7 +89,7 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol request.cancelInternal(); } } - }, request.mTimeoutMillis); + }, request.mRemoteRequest.getTimeoutMillis()); } @VisibleForTesting @@ -109,28 +107,18 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol @GuardedBy("mLock") boolean mIsFulfilled; - private final long mTimeoutMillis; - @VisibleForTesting - final int mProposedRotation; - - private final int mCurrentRotation; - private final String mPackageName; + final RotationResolutionRequest mRemoteRequest; boolean mIsDispatched; private final Object mLock = new Object(); private final long mRequestStartTimeMillis; RotationRequest( - @NonNull RotationResolverInternal.RotationResolverCallbackInternal - callbackInternal, int proposedRotation, int currentRotation, - String packageName, long timeoutMillis, - @NonNull CancellationSignal cancellationSignal) { - mTimeoutMillis = timeoutMillis; + @NonNull RotationResolverInternal.RotationResolverCallbackInternal callbackInternal, + RotationResolutionRequest request, @NonNull CancellationSignal cancellationSignal) { mCallbackInternal = callbackInternal; - mProposedRotation = proposedRotation; - mCurrentRotation = currentRotation; - mPackageName = packageName; + mRemoteRequest = request; mIRotationResolverCallback = new RotationResolverCallback(this); mCancellationSignalInternal = cancellationSignal; mRequestStartTimeMillis = SystemClock.elapsedRealtime(); @@ -185,8 +173,8 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol request.mCallbackInternal.onSuccess(rotation); final long timeToCalculate = SystemClock.elapsedRealtime() - request.mRequestStartTimeMillis; - logRotationStats(request.mProposedRotation, request.mCurrentRotation, rotation, - timeToCalculate); + logRotationStats(request.mRemoteRequest.getProposedRotation(), + request.mRemoteRequest.getCurrentRotation(), rotation, timeToCalculate); Slog.d(TAG, "onSuccess:" + rotation); Slog.d(TAG, "timeToCalculate:" + timeToCalculate); } @@ -204,8 +192,9 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol request.mCallbackInternal.onFailure(error); final long timeToCalculate = SystemClock.elapsedRealtime() - request.mRequestStartTimeMillis; - logRotationStats(request.mProposedRotation, request.mCurrentRotation, - RESOLUTION_FAILURE, timeToCalculate); + logRotationStats(request.mRemoteRequest.getProposedRotation(), + request.mRemoteRequest.getCurrentRotation(), RESOLUTION_FAILURE, + timeToCalculate); Slog.d(TAG, "onFailure:" + error); Slog.d(TAG, "timeToCalculate:" + timeToCalculate); } diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java index 13f8d61f74f5..1dbe3e485938 100644 --- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java +++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java @@ -34,11 +34,11 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.CancellationSignal; import android.rotationresolver.RotationResolverInternal; +import android.service.rotationresolver.RotationResolutionRequest; import android.service.rotationresolver.RotationResolverService; import android.text.TextUtils; import android.util.IndentingPrintWriter; import android.util.Slog; -import android.view.Surface; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -95,14 +95,14 @@ final class RotationResolverManagerPerUserService extends @VisibleForTesting void resolveRotationLocked( @NonNull RotationResolverInternal.RotationResolverCallbackInternal callbackInternal, - @Surface.Rotation int proposedRotation, @Surface.Rotation int currentRotation, - String packageName, long timeoutMillis, + @NonNull RotationResolutionRequest request, @NonNull CancellationSignal cancellationSignalInternal) { if (!isServiceAvailableLocked()) { Slog.w(TAG, "Service is not available at this moment."); callbackInternal.onFailure(ROTATION_RESULT_FAILURE_CANCELLED); - logRotationStats(proposedRotation, currentRotation, RESOLUTION_UNAVAILABLE); + logRotationStats(request.getProposedRotation(), request.getCurrentRotation(), + RESOLUTION_UNAVAILABLE); return; } @@ -114,8 +114,7 @@ final class RotationResolverManagerPerUserService extends } mCurrentRequest = new RemoteRotationResolverService.RotationRequest(callbackInternal, - proposedRotation, currentRotation, packageName, timeoutMillis, - cancellationSignalInternal); + request, cancellationSignalInternal); cancellationSignalInternal.setOnCancelListener(() -> { synchronized (mLock) { diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java index e57d4ce9ec31..a7f3cdb8bcd2 100644 --- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java +++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java @@ -35,6 +35,7 @@ import android.os.ShellCallback; import android.os.UserHandle; import android.provider.DeviceConfig; import android.rotationresolver.RotationResolverInternal; +import android.service.rotationresolver.RotationResolutionRequest; import android.text.TextUtils; import android.util.IndentingPrintWriter; import android.util.Slog; @@ -158,8 +159,9 @@ public class RotationResolverManagerService extends if (mIsServiceEnabled) { final RotationResolverManagerPerUserService service = getServiceForUserLocked( UserHandle.getCallingUserId()); - service.resolveRotationLocked(callbackInternal, proposedRotation, - currentRotation, /* packageName */ "", timeout, + final RotationResolutionRequest request = new RotationResolutionRequest("", + currentRotation, proposedRotation, true, timeout); + service.resolveRotationLocked(callbackInternal, request, cancellationSignalInternal); } else { Slog.w(TAG, "Rotation Resolver service is disabled."); diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommand.java b/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommand.java index e5088c023533..a0e04ee7a20d 100644 --- a/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommand.java +++ b/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommand.java @@ -22,6 +22,7 @@ import android.content.ComponentName; import android.os.CancellationSignal; import android.os.ShellCommand; import android.rotationresolver.RotationResolverInternal.RotationResolverCallbackInternal; +import android.service.rotationresolver.RotationResolutionRequest; import android.text.TextUtils; import android.view.Surface; @@ -107,8 +108,10 @@ final class RotationResolverShellCommand extends ShellCommand { } private int runResolveRotation() { - mService.resolveRotationLocked(sTestableRotationCallbackInternal, Surface.ROTATION_0, - Surface.ROTATION_0, "", 2000L, new CancellationSignal()); + final RotationResolutionRequest request = new RotationResolutionRequest("", + Surface.ROTATION_0, Surface.ROTATION_0, true, 2000L); + mService.resolveRotationLocked(sTestableRotationCallbackInternal, request, + new CancellationSignal()); return 0; } diff --git a/services/core/java/com/android/server/security/FileIntegrityService.java b/services/core/java/com/android/server/security/FileIntegrityService.java index 74bb99351a6d..466ac74a8322 100644 --- a/services/core/java/com/android/server/security/FileIntegrityService.java +++ b/services/core/java/com/android/server/security/FileIntegrityService.java @@ -29,6 +29,7 @@ import android.os.UserHandle; import android.security.IFileIntegrityService; import android.util.Slog; +import com.android.internal.security.VerityUtils; import com.android.server.LocalServices; import com.android.server.SystemService; diff --git a/services/core/java/com/android/server/security/OWNERS b/services/core/java/com/android/server/security/OWNERS index 91b240bcb189..e6f5826557b5 100644 --- a/services/core/java/com/android/server/security/OWNERS +++ b/services/core/java/com/android/server/security/OWNERS @@ -1,4 +1,3 @@ # Bug component: 36824 per-file FileIntegrityService.java = victorhsieh@google.com -per-file VerityUtils.java = victorhsieh@google.com diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerService.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerService.java index dbe73546d748..52c1467bd5d0 100644 --- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerService.java +++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerService.java @@ -16,6 +16,8 @@ package com.android.server.speech; +import static android.Manifest.permission.MANAGE_SPEECH_RECOGNITION; + import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.ComponentName; @@ -24,6 +26,7 @@ import android.os.IBinder; import android.os.UserHandle; import android.speech.IRecognitionServiceManager; import android.speech.IRecognitionServiceManagerCallback; +import android.util.Slog; import com.android.internal.R; import com.android.server.infra.AbstractMasterSystemService; @@ -42,6 +45,8 @@ public final class SpeechRecognitionManagerService extends SpeechRecognitionManagerServiceImpl> { private static final String TAG = SpeechRecognitionManagerService.class.getSimpleName(); + private static final int MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS = 60_000; + public SpeechRecognitionManagerService(@NonNull Context context) { super(context, // TODO(b/176578753): think if we want to favor the particular service here. @@ -58,6 +63,16 @@ public final class SpeechRecognitionManagerService extends } @Override + protected void enforceCallingPermissionForManagement() { + getContext().enforceCallingPermission(MANAGE_SPEECH_RECOGNITION, TAG); + } + + @Override + protected int getMaximumTemporaryServiceDurationMs() { + return MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS; + } + + @Override protected SpeechRecognitionManagerServiceImpl newServiceLocked( @UserIdInt int resolvedUserId, boolean disabled) { return new SpeechRecognitionManagerServiceImpl(this, mLock, resolvedUserId, disabled); @@ -77,5 +92,21 @@ public final class SpeechRecognitionManagerService extends service.createSessionLocked(componentName, clientToken, onDevice, callback); } } + + @Override + public void setTemporaryComponent(ComponentName componentName) { + int userId = UserHandle.getCallingUserId(); + if (componentName == null) { + resetTemporaryService(userId); + Slog.i(TAG, "Reset temporary service for user " + userId); + return; + } + setTemporaryService( + userId, + componentName.flattenToString(), + MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS); + Slog.i(TAG, "SpeechRecognition temporarily set to " + componentName + " for " + + MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS + "ms"); + } } } diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java index 2656a3d32555..769e049c8d0e 100644 --- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java +++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java @@ -100,6 +100,9 @@ final class SpeechRecognitionManagerServiceImpl extends } if (serviceComponent == null) { + if (mMaster.debug) { + Slog.i(TAG, "Service component is undefined, responding with error."); + } tryRespondWithError(callback, SpeechRecognizer.ERROR_CLIENT); return; } @@ -213,6 +216,10 @@ final class SpeechRecognitionManagerServiceImpl extends @Nullable private ComponentName getOnDeviceComponentNameLocked() { final String serviceName = getComponentNameLocked(); + if (mMaster.debug) { + Slog.i(TAG, "Resolved component name: " + serviceName); + } + if (serviceName == null) { if (mMaster.verbose) { Slog.v(TAG, "ensureRemoteServiceLocked(): no service component name."); @@ -241,6 +248,11 @@ final class SpeechRecognitionManagerServiceImpl extends service.getServiceComponentName().equals(serviceComponent)) .findFirst(); if (existingService.isPresent()) { + + if (mMaster.debug) { + Slog.i(TAG, "Reused existing connection to " + serviceComponent); + } + return existingService.get(); } } @@ -253,6 +265,10 @@ final class SpeechRecognitionManagerServiceImpl extends mRemoteServicesByUid.computeIfAbsent(callingUid, key -> new HashSet<>()); valuesByCaller.add(service); + if (mMaster.debug) { + Slog.i(TAG, "Creating a new connection to " + serviceComponent); + } + return service; } } diff --git a/services/core/java/com/android/server/stats/OWNERS b/services/core/java/com/android/server/stats/OWNERS index fc7fd220b26a..174ad3ad2e25 100644 --- a/services/core/java/com/android/server/stats/OWNERS +++ b/services/core/java/com/android/server/stats/OWNERS @@ -1,7 +1,10 @@ jeffreyhuang@google.com joeo@google.com +jtnguyen@google.com muhammadq@google.com +rslawik@google.com ruchirr@google.com +sharaienko@google.com singhtejinder@google.com tsaichristine@google.com yaochen@google.com diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 7ed7a592a972..8023fd42edfa 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -148,11 +148,13 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeRead import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader; import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader; import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader; +import com.android.internal.os.KernelSingleProcessCpuThreadReader.ProcessCpuUsage; import com.android.internal.os.KernelWakelockReader; import com.android.internal.os.KernelWakelockStats; import com.android.internal.os.LooperStats; import com.android.internal.os.PowerProfile; import com.android.internal.os.ProcessCpuTracker; +import com.android.internal.os.SelectedProcessCpuThreadReader; import com.android.internal.os.StoragedUidIoStatsReader; import com.android.internal.os.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes; import com.android.internal.util.CollectionUtils; @@ -351,6 +353,8 @@ public class StatsPullAtomService extends SystemService { @GuardedBy("mDataBytesTransferLock") private final ArrayList<SubInfo> mHistoricalSubs = new ArrayList<>(); + private SelectedProcessCpuThreadReader mSurfaceFlingerProcessCpuThreadReader; + // Puller locks private final Object mDataBytesTransferLock = new Object(); private final Object mBluetoothBytesTransferLock = new Object(); @@ -753,6 +757,9 @@ public class StatsPullAtomService extends SystemService { } } } + + mSurfaceFlingerProcessCpuThreadReader = + new SelectedProcessCpuThreadReader("/system/bin/surfaceflinger"); } void registerEventListeners() { @@ -1479,7 +1486,7 @@ public class StatsPullAtomService extends SystemService { } for (int freqIndex = 0; freqIndex < timesMs.length; ++freqIndex) { int cluster = freqsClusters[freqIndex]; - long freq = freqs[freqIndex]; + int freq = (int) freqs[freqIndex]; long timeMs = timesMs[freqIndex]; pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, cluster, freq, timeMs)); } @@ -1678,6 +1685,18 @@ public class StatsPullAtomService extends SystemService { FrameworkStatsLog.CPU_CYCLES_PER_THREAD_GROUP_CLUSTER__THREAD_GROUP__SYSTEM_SERVER_BINDER, times.binderThreadCpuTimesUs); + ProcessCpuUsage surfaceFlingerTimes = mSurfaceFlingerProcessCpuThreadReader.readAbsolute(); + if (surfaceFlingerTimes != null && surfaceFlingerTimes.threadCpuTimesMillis != null) { + long[] surfaceFlingerTimesUs = + new long[surfaceFlingerTimes.threadCpuTimesMillis.length]; + for (int i = 0; i < surfaceFlingerTimesUs.length; ++i) { + surfaceFlingerTimesUs[i] = surfaceFlingerTimes.threadCpuTimesMillis[i] * 1_000; + } + addCpuCyclesPerThreadGroupClusterAtoms(atomTag, pulledData, + FrameworkStatsLog.CPU_CYCLES_PER_THREAD_GROUP_CLUSTER__THREAD_GROUP__SURFACE_FLINGER, + surfaceFlingerTimesUs); + } + return StatsManager.PULL_SUCCESS; } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index 7523671fb3a7..970420a284d6 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -160,4 +160,10 @@ public interface StatusBarManagerInternal { * Handles a logging command from the WM shell command. */ void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd); + + /** + * @see com.android.internal.statusbar.IStatusBar#setNavigationBarLumaSamplingEnabled(int, + * boolean) + */ + void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 546e420c1d59..302a23fb262c 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -588,6 +588,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } catch (RemoteException ex) { } } } + + @Override + public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) { + if (mBar != null) { + try { + mBar.setNavigationBarLumaSamplingEnabled(displayId, enable); + } catch (RemoteException ex) { } + } + } }; private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() { diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java index 3ae9d641e81c..ee78a4e4d1cf 100644 --- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java +++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java @@ -28,8 +28,6 @@ import android.app.time.TimeZoneCapabilitiesAndConfig; import android.app.time.TimeZoneConfiguration; import android.os.UserHandle; -import com.android.internal.util.Preconditions; - import java.util.Objects; /** @@ -39,7 +37,7 @@ import java.util.Objects; */ public final class ConfigurationInternal { - private final boolean mAutoDetectionSupported; + private final boolean mTelephonyDetectionSupported; private final boolean mGeoDetectionSupported; private final boolean mAutoDetectionEnabled; private final @UserIdInt int mUserId; @@ -48,7 +46,7 @@ public final class ConfigurationInternal { private final boolean mGeoDetectionEnabled; private ConfigurationInternal(Builder builder) { - mAutoDetectionSupported = builder.mAutoDetectionSupported; + mTelephonyDetectionSupported = builder.mTelephonyDetectionSupported; mGeoDetectionSupported = builder.mGeoDetectionSupported; mAutoDetectionEnabled = builder.mAutoDetectionEnabled; @@ -56,14 +54,16 @@ public final class ConfigurationInternal { mUserConfigAllowed = builder.mUserConfigAllowed; mLocationEnabled = builder.mLocationEnabled; mGeoDetectionEnabled = builder.mGeoDetectionEnabled; - // if mGeoDetectionSupported then mAutoDetectionSupported, i.e. mGeoDetectionSupported - // cannot be true if mAutoDetectionSupported == false - Preconditions.checkState(mAutoDetectionSupported || !mGeoDetectionSupported); } /** Returns true if the device supports any form of auto time zone detection. */ public boolean isAutoDetectionSupported() { - return mAutoDetectionSupported; + return mTelephonyDetectionSupported || mGeoDetectionSupported; + } + + /** Returns true if the device supports telephony time zone detection. */ + public boolean isTelephonyDetectionSupported() { + return mTelephonyDetectionSupported; } /** Returns true if the device supports geolocation time zone detection. */ @@ -78,9 +78,10 @@ public final class ConfigurationInternal { /** * Returns true if auto time zone detection behavior is actually enabled, which can be distinct - * from the raw setting value. */ + * from the raw setting value. + */ public boolean getAutoDetectionEnabledBehavior() { - return mAutoDetectionSupported && mAutoDetectionEnabled; + return isAutoDetectionSupported() && mAutoDetectionEnabled; } /** Returns the ID of the user this configuration is associated with. */ @@ -212,7 +213,7 @@ public final class ConfigurationInternal { ConfigurationInternal that = (ConfigurationInternal) o; return mUserId == that.mUserId && mUserConfigAllowed == that.mUserConfigAllowed - && mAutoDetectionSupported == that.mAutoDetectionSupported + && mTelephonyDetectionSupported == that.mTelephonyDetectionSupported && mGeoDetectionSupported == that.mGeoDetectionSupported && mAutoDetectionEnabled == that.mAutoDetectionEnabled && mLocationEnabled == that.mLocationEnabled @@ -221,7 +222,7 @@ public final class ConfigurationInternal { @Override public int hashCode() { - return Objects.hash(mUserId, mUserConfigAllowed, mAutoDetectionSupported, + return Objects.hash(mUserId, mUserConfigAllowed, mTelephonyDetectionSupported, mGeoDetectionSupported, mAutoDetectionEnabled, mLocationEnabled, mGeoDetectionEnabled); } @@ -231,7 +232,7 @@ public final class ConfigurationInternal { return "ConfigurationInternal{" + "mUserId=" + mUserId + ", mUserConfigAllowed=" + mUserConfigAllowed - + ", mAutoDetectionSupported=" + mAutoDetectionSupported + + ", mTelephonyDetectionSupported=" + mTelephonyDetectionSupported + ", mGeoDetectionSupported=" + mGeoDetectionSupported + ", mAutoDetectionEnabled=" + mAutoDetectionEnabled + ", mLocationEnabled=" + mLocationEnabled @@ -247,7 +248,7 @@ public final class ConfigurationInternal { private final @UserIdInt int mUserId; private boolean mUserConfigAllowed; - private boolean mAutoDetectionSupported; + private boolean mTelephonyDetectionSupported; private boolean mGeoDetectionSupported; private boolean mAutoDetectionEnabled; private boolean mLocationEnabled; @@ -266,7 +267,7 @@ public final class ConfigurationInternal { public Builder(ConfigurationInternal toCopy) { this.mUserId = toCopy.mUserId; this.mUserConfigAllowed = toCopy.mUserConfigAllowed; - this.mAutoDetectionSupported = toCopy.mAutoDetectionSupported; + this.mTelephonyDetectionSupported = toCopy.mTelephonyDetectionSupported; this.mGeoDetectionSupported = toCopy.mGeoDetectionSupported; this.mAutoDetectionEnabled = toCopy.mAutoDetectionEnabled; this.mLocationEnabled = toCopy.mLocationEnabled; @@ -282,10 +283,10 @@ public final class ConfigurationInternal { } /** - * Sets whether any form of automatic time zone detection is supported on this device. + * Sets whether telephony time zone detection is supported on this device. */ - public Builder setAutoDetectionFeatureSupported(boolean supported) { - mAutoDetectionSupported = supported; + public Builder setTelephonyDetectionFeatureSupported(boolean supported) { + mTelephonyDetectionSupported = supported; return this; } diff --git a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java index e3caae9482d9..0e5f3bfbb4b1 100644 --- a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java +++ b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java @@ -128,8 +128,8 @@ public final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Envir @Override public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) { return new ConfigurationInternal.Builder(userId) - .setAutoDetectionFeatureSupported( - mServiceConfigAccessor.isAutoDetectionFeatureSupported()) + .setTelephonyDetectionFeatureSupported( + mServiceConfigAccessor.isTelephonyTimeZoneDetectionFeatureSupported()) .setGeoDetectionFeatureSupported( mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported()) .setAutoDetectionEnabled(isAutoDetectionEnabled()) diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java index 86c32f8d7b45..2452c8d3ddc9 100644 --- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java +++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java @@ -115,10 +115,15 @@ public final class ServiceConfigAccessor { /** Returns {@code true} if any form of automatic time zone detection is supported. */ public boolean isAutoDetectionFeatureSupported() { - return deviceHasTelephonyNetwork() || isGeoTimeZoneDetectionFeatureSupported(); + return isTelephonyTimeZoneDetectionFeatureSupported() + || isGeoTimeZoneDetectionFeatureSupported(); } - private boolean deviceHasTelephonyNetwork() { + /** + * Returns {@code true} if the telephony-based time zone detection feature is supported on the + * device. + */ + public boolean isTelephonyTimeZoneDetectionFeatureSupported() { // TODO b/150583524 Avoid the use of a deprecated API. return mContext.getSystemService(ConnectivityManager.class) .isNetworkSupported(ConnectivityManager.TYPE_MOBILE); diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java index 2d5dacdd6acc..7ba20eee0392 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java @@ -86,7 +86,7 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter @NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) { Objects.requireNonNull(timeZoneSuggestion); - // All strategy calls must take place on the mHandler thread. + // This call can take place on the mHandler thread because there is no return value. mHandler.post( () -> mTimeZoneDetectorStrategy.suggestGeolocationTimeZone(timeZoneSuggestion)); } diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java index d163a0e22320..2e96a1065af4 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java @@ -195,6 +195,13 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat private ReferenceWithHistory<GeolocationTimeZoneSuggestion> mLatestGeoLocationSuggestion = new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE); + /** + * The latest manual suggestion received. + */ + @GuardedBy("this") + private ReferenceWithHistory<ManualTimeZoneSuggestion> mLatestManualSuggestion = + new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE); + @GuardedBy("this") private final List<Dumpable> mDumpables = new ArrayList<>(); @@ -286,6 +293,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat if (currentUserConfig.getGeoDetectionEnabledBehavior()) { // Only store a geolocation suggestion if geolocation detection is currently enabled. + // See also clearGeolocationSuggestionIfNeeded(). mLatestGeoLocationSuggestion.set(suggestion); // Now perform auto time zone detection. The new suggestion may be used to modify the @@ -324,6 +332,12 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat return false; } + // Record the manual suggestion for debugging / metrics (but only if manual detection is + // currently enabled). + // Note: This is not used to set the device back to a previous manual suggestion if the user + // later disables automatic time zone detection. + mLatestManualSuggestion.set(suggestion); + setDeviceTimeZoneIfRequired(timeZoneId, cause); return true; } @@ -619,6 +633,11 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat mTimeZoneChangesLog.dump(ipw); ipw.decreaseIndent(); // level 2 + ipw.println("Manual suggestion history:"); + ipw.increaseIndent(); // level 2 + mLatestManualSuggestion.dump(ipw); + ipw.decreaseIndent(); // level 2 + ipw.println("Geolocation suggestion history:"); ipw.increaseIndent(); // level 2 mLatestGeoLocationSuggestion.dump(ipw); @@ -639,6 +658,14 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat * A method used to inspect strategy state during tests. Not intended for general use. */ @VisibleForTesting + public synchronized ManualTimeZoneSuggestion getLatestManualSuggestion() { + return mLatestManualSuggestion.get(); + } + + /** + * A method used to inspect strategy state during tests. Not intended for general use. + */ + @VisibleForTesting public synchronized QualifiedTelephonyTimeZoneSuggestion getLatestTelephonySuggestion( int slotIndex) { return mTelephonySuggestionsBySlotIndex.get(slotIndex); diff --git a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java index c0c9e6d58622..417a6368be4c 100644 --- a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java +++ b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java @@ -39,15 +39,13 @@ import java.util.Objects; */ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider { - private static final String TAG = LocationTimeZoneManagerService.TAG; - @NonNull private final LocationTimeZoneProviderProxy mProxy; BinderLocationTimeZoneProvider( @NonNull ThreadingDomain threadingDomain, @NonNull String providerName, @NonNull LocationTimeZoneProviderProxy proxy) { - super(threadingDomain, providerName); + super(threadingDomain, providerName, new ZoneInfoDbTimeZoneIdValidator()); mProxy = Objects.requireNonNull(proxy); } diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java index 0d1692a8781d..588382158bc9 100644 --- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java +++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java @@ -520,6 +520,12 @@ public class LocationTimeZoneManagerService extends Binder { } } + static void infoLog(String msg) { + if (Log.isLoggable(TAG, Log.INFO)) { + Slog.i(TAG, msg); + } + } + static void warnLog(String msg) { warnLog(msg, null); } diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java index ef2f357b8c3e..b97c838017eb 100644 --- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java +++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java @@ -20,6 +20,7 @@ import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESU import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_SUCCESS_KEY; import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.debugLog; +import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.infoLog; import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.warnLog; import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED; import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED; @@ -85,6 +86,18 @@ abstract class LocationTimeZoneProvider implements Dumpable { } /** + * Used by {@link LocationTimeZoneProvider} to check if time zone IDs are understood + * by the platform. + */ + interface TimeZoneIdValidator { + + /** + * Returns whether {@code timeZoneId} is supported by the platform or not. + */ + boolean isValid(@NonNull String timeZoneId); + } + + /** * Information about the provider's current state. */ static class ProviderState { @@ -364,13 +377,17 @@ abstract class LocationTimeZoneProvider implements Dumpable { // Non-null and effectively final after initialize() is called. ProviderListener mProviderListener; + @NonNull private TimeZoneIdValidator mTimeZoneIdValidator; + /** Creates the instance. */ LocationTimeZoneProvider(@NonNull ThreadingDomain threadingDomain, - @NonNull String providerName) { + @NonNull String providerName, + @NonNull TimeZoneIdValidator timeZoneIdValidator) { mThreadingDomain = Objects.requireNonNull(threadingDomain); mInitializationTimeoutQueue = threadingDomain.createSingleRunnableQueue(); mSharedLock = threadingDomain.getLockObject(); mProviderName = Objects.requireNonNull(providerName); + mTimeZoneIdValidator = Objects.requireNonNull(timeZoneIdValidator); } /** @@ -610,6 +627,25 @@ abstract class LocationTimeZoneProvider implements Dumpable { mThreadingDomain.assertCurrentThread(); Objects.requireNonNull(timeZoneProviderEvent); + // If the provider has made a suggestion with unknown time zone IDs it cannot be used to set + // the device's time zone. This logic prevents bad time zone IDs entering the time zone + // detection logic from third party code. + // + // An event containing an unknown time zone ID could occur if the provider is using a + // different TZDB version than the device. Provider developers are expected to take steps to + // avoid version skew problem, e.g. by ensuring atomic updates with the platform time zone + // rules, or providing IDs based on the device's TZDB version, so this is not considered a + // common case. + // + // Treating a suggestion containing unknown time zone IDs as "uncertain" in the primary + // enables immediate failover to a secondary provider, one that might provide valid IDs for + // the same location, which should provide better behavior than just ignoring the event. + if (hasInvalidTimeZones(timeZoneProviderEvent)) { + infoLog("event=" + timeZoneProviderEvent + " has unsupported time zones. " + + "Replacing it with uncertain event."); + timeZoneProviderEvent = TimeZoneProviderEvent.createUncertainEvent(); + } + synchronized (mSharedLock) { debugLog("handleTimeZoneProviderEvent: mProviderName=" + mProviderName + ", timeZoneProviderEvent=" + timeZoneProviderEvent); @@ -707,6 +743,20 @@ abstract class LocationTimeZoneProvider implements Dumpable { } } + private boolean hasInvalidTimeZones(@NonNull TimeZoneProviderEvent event) { + if (event.getSuggestion() == null) { + return false; + } + + for (String timeZone : event.getSuggestion().getTimeZoneIds()) { + if (!mTimeZoneIdValidator.isValid(timeZone)) { + return true; + } + } + + return false; + } + @GuardedBy("mSharedLock") private void assertIsStarted() { ProviderState currentState = mCurrentState.get(); diff --git a/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidator.java b/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidator.java new file mode 100644 index 000000000000..cab5ad25c54e --- /dev/null +++ b/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidator.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.timezonedetector.location; + +import android.annotation.NonNull; + +import com.android.i18n.timezone.ZoneInfoDb; + +class ZoneInfoDbTimeZoneIdValidator implements + LocationTimeZoneProvider.TimeZoneIdValidator { + + @Override + public boolean isValid(@NonNull String timeZoneId) { + return ZoneInfoDb.getInstance().hasTimeZone(timeZoneId); + } +} diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java index b2db9f5af07e..8dcc547508ec 100644 --- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -23,7 +23,6 @@ import android.net.ConnectivityManager.NetworkCallback; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkCapabilities.NetCapability; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.os.Handler; @@ -115,33 +114,61 @@ public class UnderlyingNetworkTracker { getWifiNetworkRequest(), mHandler, mWifiBringupCallback); updateSubIdsAndCellularRequests(); - // register Network-selection request used to decide selected underlying Network + // Register Network-selection request used to decide selected underlying Network. All + // underlying networks must be VCN managed in order to be used. mConnectivityManager.requestBackgroundNetwork( - getNetworkRequestBase().build(), mHandler, mRouteSelectionCallback); + getBaseNetworkRequest(true /* requireVcnManaged */).build(), + mHandler, + mRouteSelectionCallback); } private NetworkRequest getWifiNetworkRequest() { - return getNetworkRequestBase().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(); + // Request exclusively VCN managed networks to ensure that we only ever keep carrier wifi + // alive. + return getBaseNetworkRequest(true /* requireVcnManaged */) + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); } private NetworkRequest getCellNetworkRequestForSubId(int subId) { - return getNetworkRequestBase() + // Do not request NOT_VCN_MANAGED to ensure that the TelephonyNetworkFactory has a + // fulfillable request to bring up underlying cellular Networks even if the VCN is already + // connected. + return getBaseNetworkRequest(false /* requireVcnManaged */) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) .build(); } - private NetworkRequest.Builder getNetworkRequestBase() { - NetworkRequest.Builder requestBase = new NetworkRequest.Builder(); - for (@NetCapability int capability : mRequiredUnderlyingNetworkCapabilities) { + /** + * Builds and returns a NetworkRequest builder common to all Underlying Network requests + * + * <p>A NetworkRequest may either (1) Require the presence of a capability by using + * addCapability(), (2) require the absence of a capability using unwanted capabilities, or (3) + * allow any state. Underlying networks are never desired to have the NOT_VCN_MANAGED + * capability, and only cases (2) and (3) are used. + * + * @param requireVcnManaged whether the underlying network is required to be VCN managed to + * match this request. If {@code true}, the NOT_VCN_MANAGED capability will be set as + * unwanted. Else, the NOT_VCN_MANAGED capability will be removed, and any state is + * acceptable. + */ + private NetworkRequest.Builder getBaseNetworkRequest(boolean requireVcnManaged) { + NetworkRequest.Builder requestBase = + new NetworkRequest.Builder() + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + + for (int capability : mRequiredUnderlyingNetworkCapabilities) { requestBase.addCapability(capability); } - return requestBase - .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + if (requireVcnManaged) { + requestBase.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } + + return requestBase; } /** diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java index c55913e2e547..3f74938005a7 100644 --- a/services/core/java/com/android/server/vcn/Vcn.java +++ b/services/core/java/com/android/server/vcn/Vcn.java @@ -299,9 +299,7 @@ public class Vcn extends Handler { for (VcnGatewayConnectionConfig gatewayConnectionConfig : mConfig.getGatewayConnectionConfigs()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { - Slog.v( - getLogTag(), - "Bringing up new VcnGatewayConnection for request " + request.requestId); + Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request); final VcnGatewayConnection vcnGatewayConnection = mDeps.newVcnGatewayConnection( diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 15429f455d6e..69a153f79a1b 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -20,6 +20,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR; @@ -59,6 +60,7 @@ import android.net.ipsec.ike.exceptions.AuthenticationFailedException; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; +import android.net.vcn.VcnControlPlaneIkeConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; @@ -1348,7 +1350,7 @@ public class VcnGatewayConnection extends StateMachine { mIkeSession = null; } - mIkeSession = buildIkeSession(); + mIkeSession = buildIkeSession(mUnderlying.network); } @Override @@ -1726,6 +1728,7 @@ public class VcnGatewayConnection extends StateMachine { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); builder.addTransportType(TRANSPORT_CELLULAR); + builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); builder.addCapability(NET_CAPABILITY_NOT_CONGESTED); builder.addCapability(NET_CAPABILITY_NOT_SUSPENDED); @@ -1939,23 +1942,29 @@ public class VcnGatewayConnection extends StateMachine { new EventDisconnectRequestedInfo(reason, shouldQuit)); } - private IkeSessionParams buildIkeParams() { - // TODO: Implement this once IkeSessionParams is persisted - return null; + private IkeSessionParams buildIkeParams(@NonNull Network network) { + final VcnControlPlaneIkeConfig controlPlaneConfig = + (VcnControlPlaneIkeConfig) mConnectionConfig.getControlPlaneConfig(); + final IkeSessionParams.Builder builder = + new IkeSessionParams.Builder(controlPlaneConfig.getIkeSessionParams()); + builder.setConfiguredNetwork(network); + + return builder.build(); } private ChildSessionParams buildChildParams() { - // TODO: Implement this once IkeSessionParams is persisted - return null; + final VcnControlPlaneIkeConfig controlPlaneConfig = + (VcnControlPlaneIkeConfig) mConnectionConfig.getControlPlaneConfig(); + return controlPlaneConfig.getChildSessionParams(); } @VisibleForTesting(visibility = Visibility.PRIVATE) - VcnIkeSession buildIkeSession() { + VcnIkeSession buildIkeSession(@NonNull Network network) { final int token = ++mCurrentToken; return mDeps.newIkeSession( mVcnContext, - buildIkeParams(), + buildIkeParams(network), buildChildParams(), new IkeSessionCallbackImpl(token), new VcnChildSessionCallback(token)); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5446a39fad86..db3d7ad0c398 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; import static android.app.ActivityOptions.ANIM_CLIP_REVEAL; @@ -84,8 +85,12 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VER import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; +import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_METADATA; +import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_OVERRIDE; +import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE; import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; import static android.content.pm.ActivityInfo.isFixedOrientationPortrait; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.res.Configuration.EMPTY; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; @@ -132,6 +137,7 @@ import static com.android.server.wm.ActivityRecordProto.CLIENT_VISIBLE; import static com.android.server.wm.ActivityRecordProto.DEFER_HIDING_CLIENT; import static com.android.server.wm.ActivityRecordProto.FILLS_PARENT; import static com.android.server.wm.ActivityRecordProto.FRONT_OF_TASK; +import static com.android.server.wm.ActivityRecordProto.IN_SIZE_COMPAT_MODE; import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING; import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START; import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN; @@ -205,6 +211,7 @@ import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowContainerChildProto.ACTIVITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -278,6 +285,7 @@ import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.os.storage.StorageManager; +import android.permission.PermissionManager; import android.service.dreams.DreamActivity; import android.service.dreams.DreamManagerInternal; import android.service.voice.IVoiceInteractionSession; @@ -2107,7 +2115,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } if (abort) { - surface.remove(); + surface.remove(false /* prepareAnimation */); } } else { ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Surface returned was null: %s", @@ -2121,7 +2129,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, TaskSnapshot snapshot) { - if (newTask || !processRunning || (taskSwitch && !activityCreated)) { + if ((newTask || !processRunning || (taskSwitch && !activityCreated)) + && !isActivityTypeHome()) { return STARTING_WINDOW_TYPE_SPLASH_SCREEN; } else if (taskSwitch && allowTaskSnapshot) { if (isSnapshotCompatible(snapshot)) { @@ -2172,7 +2181,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A + ActivityRecord.this + " state " + mTransferringSplashScreenState); if (isTransferringSplashScreen()) { mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH; - // TODO show default exit splash screen animation removeStartingWindow(); } } @@ -2189,6 +2197,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } private boolean transferSplashScreenIfNeeded() { + if (!mWmService.mStartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER) { + return false; + } if (!mHandleExitSplashScreen || mStartingSurface == null || mStartingWindow == null || mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_FINISH) { return false; @@ -2258,10 +2269,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } // no matter what, remove the starting window. mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH; - removeStartingWindow(); + removeStartingWindowAnimation(false /* prepareAnimation */); } void removeStartingWindow() { + removeStartingWindowAnimation(true /* prepareAnimation */); + } + + void removeStartingWindowAnimation(boolean prepareAnimation) { if (transferSplashScreenIfNeeded()) { return; } @@ -2306,7 +2321,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mWmService.mAnimationHandler.post(() -> { ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing startingView=%s", surface); try { - surface.remove(); + surface.remove(prepareAnimation); } catch (Exception e) { Slog.w(TAG_WM, "Exception when removing starting window", e); } @@ -6183,7 +6198,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Remove orphaned starting window. if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this); mStartingWindowState = STARTING_WINDOW_REMOVED; - removeStartingWindow(); + removeStartingWindowAnimation(false /* prepareAnimation */); } if (isState(INITIALIZING) && !shouldBeVisible( true /* behindFullscreenActivity */, true /* ignoringKeyguard */)) { @@ -6815,8 +6830,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * aspect ratio. */ boolean shouldCreateCompatDisplayInsets() { - if (info.supportsSizeChanges() != ActivityInfo.SIZE_CHANGES_UNSUPPORTED) { - return false; + switch (info.supportsSizeChanges()) { + case SIZE_CHANGES_SUPPORTED_METADATA: + case SIZE_CHANGES_SUPPORTED_OVERRIDE: + return false; + case SIZE_CHANGES_UNSUPPORTED_OVERRIDE: + return true; + default: + // Fall through } if (inMultiWindowMode() || getWindowConfiguration().hasWindowDecorCaption()) { final ActivityRecord root = task != null ? task.getRootActivity() : null; @@ -6955,6 +6976,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // layout traversals. mConfigurationSeq = Math.max(++mConfigurationSeq, 1); getResolvedOverrideConfiguration().seq = mConfigurationSeq; + + // Sandbox max bounds by setting it to the app bounds, if activity is letterboxed or in + // size compat mode. + if (providesMaxBounds()) { + if (DEBUG_CONFIGURATION) { + ProtoLog.d(WM_DEBUG_CONFIGURATION, "Sandbox max bounds for uid %s to bounds %s " + + "due to letterboxing from mismatch with parent bounds? %s size compat " + + "mode %s", getUid(), + resolvedConfig.windowConfiguration.getBounds(), !matchParentBounds(), + inSizeCompatMode()); + } + resolvedConfig.windowConfiguration + .setMaxBounds(resolvedConfig.windowConfiguration.getBounds()); + } } /** @@ -7296,6 +7331,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return super.getBounds(); } + @Override + public boolean providesMaxBounds() { + // System and SystemUI should always be able to access the physical display bounds, + // so do not provide it with the overridden maximum bounds. + // TODO(b/179179513) check WindowState#mOwnerCanAddInternalSystemWindow instead + if (getUid() == SYSTEM_UID || PermissionManager.checkPermission(INTERNAL_SYSTEM_WINDOW, + getPid(), info.applicationInfo.uid) == PERMISSION_GRANTED) { + return false; + } + // Max bounds should be sandboxed where an activity is letterboxed (activity bounds will be + // smaller than task bounds) or put in size compat mode. + return !matchParentBounds() || inSizeCompatMode(); + } + @VisibleForTesting @Override Rect getAnimationBounds(int appRootTaskClipMode) { @@ -8214,6 +8263,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A proto.write(PROC_ID, app.getPid()); } proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled()); + proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode()); } @Override diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java index 13295e8aca02..128d452c3018 100644 --- a/services/core/java/com/android/server/wm/BlurController.java +++ b/services/core/java/com/android/server/wm/BlurController.java @@ -22,12 +22,17 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.view.ICrossWindowBlurEnabledListener; +import com.android.internal.annotations.GuardedBy; + final class BlurController { private final RemoteCallbackList<ICrossWindowBlurEnabledListener> mBlurEnabledListeners = new RemoteCallbackList<>(); private final Object mLock = new Object(); + @GuardedBy("mLock") boolean mBlurEnabled; + @GuardedBy("mLock") + boolean mBlurForceDisabled; BlurController() { mBlurEnabled = CROSS_WINDOW_BLUR_SUPPORTED; @@ -46,19 +51,24 @@ final class BlurController { mBlurEnabledListeners.unregister(listener); } - private void updateBlurEnabled() { - // TODO: add other factors disabling blurs - final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED; + void setForceCrossWindowBlurDisabled(boolean disable) { synchronized (mLock) { - if (mBlurEnabled == newEnabled) { - return; - } - mBlurEnabled = newEnabled; - notifyBlurEnabledChanged(newEnabled); + mBlurForceDisabled = disable; + updateBlurEnabledLocked(); + } + + } + + private void updateBlurEnabledLocked() { + final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurForceDisabled; + if (mBlurEnabled == newEnabled) { + return; } + mBlurEnabled = newEnabled; + notifyBlurEnabledChangedLocked(newEnabled); } - private void notifyBlurEnabledChanged(boolean enabled) { + private void notifyBlurEnabledChangedLocked(boolean enabled) { int i = mBlurEnabledListeners.beginBroadcast(); while (i > 0) { i--; @@ -71,6 +81,4 @@ final class BlurController { } mBlurEnabledListeners.finishBroadcast(); } - - } diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index 62a00802896f..8fbe1775fd19 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -367,8 +367,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { * Returns {@code true} if this {@link ConfigurationContainer} provides the maximum bounds to * its child {@link ConfigurationContainer}s. Returns {@code false}, otherwise. * <p> - * The maximum bounds is how large a window can be expanded. Currently only - * {@link DisplayContent} and {@link DisplayArea} effect this property. + * The maximum bounds is how large a window can be expanded. * </p> */ protected boolean providesMaxBounds() { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 1d45c6e1a371..426e63181ff1 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -131,7 +131,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE; import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT; import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD; -import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS; @@ -1811,11 +1810,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp w.mReportOrientationChanged = true; }, true /* traverseTopToBottom */); - if (rotateSeamlessly) { - mWmService.mH.sendNewMessageDelayed(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT, - this, SEAMLESS_ROTATION_TIMEOUT_DURATION); - } - for (int i = mWmService.mRotationWatchers.size() - 1; i >= 0; i--) { final WindowManagerService.RotationWatcher rotationWatcher = mWmService.mRotationWatchers.get(i); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 32152ec85493..01f0359fa548 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1410,9 +1410,9 @@ public class DisplayPolicy { boolean localClient) { final InsetsState state = mDisplayContent.getInsetsPolicy().getInsetsForWindowMetrics(attrs); - final boolean inSizeCompatMode = WindowState.inSizeCompatMode(attrs, windowToken); - outInsetsState.set(state, inSizeCompatMode || localClient); - if (inSizeCompatMode) { + final boolean hasCompatScale = WindowState.hasCompatScale(attrs, windowToken); + outInsetsState.set(state, hasCompatScale || localClient); + if (hasCompatScale) { final float compatScale = windowToken != null ? windowToken.getSizeCompatScale() : mDisplayContent.mCompatibleScreenScale; diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 63cb38a59349..5df1355f3460 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -567,7 +567,7 @@ public class DisplayRotation { } mDisplayContent.forAllWindows(w -> { if (w.mSeamlesslyRotated) { - w.finishSeamlessRotation(false /* timeout */); + w.cancelSeamlessRotation(); w.mSeamlesslyRotated = false; } }, true /* traverseTopToBottom */); @@ -670,24 +670,6 @@ public class DisplayRotation { } } - void onSeamlessRotationTimeout() { - final boolean[] isLayoutNeeded = { false }; - - mDisplayContent.forAllWindows(w -> { - if (!w.mSeamlesslyRotated) { - return; - } - isLayoutNeeded[0] = true; - w.setDisplayLayoutNeeded(); - w.finishSeamlessRotation(true /* timeout */); - markForSeamlessRotation(w, false /* seamlesslyRotated */); - }, true /* traverseTopToBottom */); - - if (isLayoutNeeded[0]) { - mService.mWindowPlacerLocked.performSurfacePlacement(); - } - } - /** * Returns the animation to run for a rotation transition based on the top fullscreen windows * {@link android.view.WindowManager.LayoutParams#rotationAnimation} and whether it is currently diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index 627af9149fe5..1120a074aa8c 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -182,8 +182,6 @@ class DragDropController { if (SHOW_LIGHT_TRANSACTIONS) { Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag"); } - - mDragState.notifyLocationLocked(touchX, touchY); } finally { if (surface != null) { surface.release(); diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 0b3c065e0e73..08d5e800a808 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -515,50 +515,6 @@ class DragState { mTransaction.setPosition(mSurfaceControl, x - mThumbOffsetX, y - mThumbOffsetY).apply(); ProtoLog.i(WM_SHOW_TRANSACTIONS, "DRAG %s: pos=(%d,%d)", mSurfaceControl, (int) (x - mThumbOffsetX), (int) (y - mThumbOffsetY)); - - notifyLocationLocked(x, y); - } - - void notifyLocationLocked(float x, float y) { - // Tell the affected window - WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y); - if (touchedWin != null && !isWindowNotified(touchedWin)) { - // The drag point is over a window which was not notified about a drag start. - // Pretend it's over empty space. - touchedWin = null; - } - - try { - final int myPid = Process.myPid(); - - // have we dragged over a new window? - if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) { - if (DEBUG_DRAG) { - Slog.d(TAG_WM, "sending DRAG_EXITED to " + mTargetWindow); - } - // force DRAG_EXITED_EVENT if appropriate - DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED, - 0, 0, 0, 0, null, null, null, null, null, false); - mTargetWindow.mClient.dispatchDragEvent(evt); - if (myPid != mTargetWindow.mSession.mPid) { - evt.recycle(); - } - } - if (touchedWin != null) { - if (false && DEBUG_DRAG) { - Slog.d(TAG_WM, "sending DRAG_LOCATION to " + touchedWin); - } - DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION, - x, y, mThumbOffsetX, mThumbOffsetY, null, null, null, null, null, false); - touchedWin.mClient.dispatchDragEvent(evt); - if (myPid != touchedWin.mSession.mPid) { - evt.recycle(); - } - } - } catch (RemoteException e) { - Slog.w(TAG_WM, "can't send drag notification to windows"); - } - mTargetWindow = touchedWin; } /** diff --git a/services/core/java/com/android/server/wm/FixedRotationAnimationController.java b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java index a1e3ac71a3b6..aa7317022794 100644 --- a/services/core/java/com/android/server/wm/FixedRotationAnimationController.java +++ b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java @@ -37,10 +37,15 @@ public class FixedRotationAnimationController extends FadeAnimationController { super(displayContent); final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy(); mStatusBar = displayPolicy.getStatusBar(); - // Do not animate movable navigation bar (e.g. non-gesture mode). + + final RecentsAnimationController controller = + displayContent.mWmService.getRecentsAnimationController(); + final boolean navBarControlledByRecents = + controller != null && controller.isNavigationBarAttachedToApp(); + // Do not animate movable navigation bar (e.g. non-gesture mode) or when the navigation bar + // is currently controlled by recents animation. mNavigationBar = !displayPolicy.navigationBarCanMove() - ? displayPolicy.getNavigationBar() - : null; + && !navBarControlledByRecents ? displayPolicy.getNavigationBar() : null; } /** Applies show animation on the previously hidden window tokens. */ diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index c6c7fe083b16..35e54912b33e 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -30,7 +30,6 @@ import static com.android.server.wm.InsetsSourceProviderProto.CONTROLLABLE; import static com.android.server.wm.InsetsSourceProviderProto.CONTROL_TARGET; import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL; import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL_TARGET; -import static com.android.server.wm.InsetsSourceProviderProto.FINISH_SEAMLESS_ROTATE_FRAME_NUMBER; import static com.android.server.wm.InsetsSourceProviderProto.FRAME; import static com.android.server.wm.InsetsSourceProviderProto.IME_OVERRIDDEN_FRAME; import static com.android.server.wm.InsetsSourceProviderProto.IS_LEASH_READY_FOR_DISPATCHING; @@ -59,6 +58,7 @@ import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import java.io.PrintWriter; +import java.util.function.Consumer; /** * Controller for a specific inset source on the server. It's called provider as it provides the @@ -84,6 +84,16 @@ class InsetsSourceProvider { private final Rect mImeOverrideFrame = new Rect(); private boolean mIsLeashReadyForDispatching; + private final Consumer<Transaction> mSetLeashPositionConsumer = t -> { + if (mControl != null) { + final SurfaceControl leash = mControl.getLeash(); + if (leash != null) { + final Point position = mControl.getSurfacePosition(); + t.setPosition(leash, position.x, position.y); + } + } + }; + /** The visibility override from the current controlling window. */ private boolean mClientVisible; @@ -93,7 +103,6 @@ class InsetsSourceProvider { private boolean mServerVisible; private boolean mSeamlessRotating; - private long mFinishSeamlessRotateFrameNumber = -1; private final boolean mControllable; @@ -150,7 +159,6 @@ class InsetsSourceProvider { // TODO: Ideally, we should wait for the animation to finish so previous window can // animate-out as new one animates-in. mWin.cancelAnimation(); - mWin.mPendingPositionChanged = null; mWin.mProvidedInsetsSources.remove(mSource.getType()); } ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win); @@ -249,31 +257,16 @@ class InsetsSourceProvider { if (mControl != null) { final Point position = getWindowFrameSurfacePosition(); if (mControl.setSurfacePosition(position.x, position.y) && mControlTarget != null) { - if (!mWin.getWindowFrames().didFrameSizeChange()) { - updateLeashPosition(-1 /* frameNumber */); - } else if (mWin.mInRelayout) { - updateLeashPosition(mWin.getFrameNumber()); + if (mWin.getWindowFrames().didFrameSizeChange()) { + mWin.applyWithNextDraw(mSetLeashPositionConsumer); } else { - mWin.mPendingPositionChanged = this; + mSetLeashPositionConsumer.accept(mWin.getPendingTransaction()); } mStateController.notifyControlChanged(mControlTarget); } } } - void updateLeashPosition(long frameNumber) { - if (mControl == null) { - return; - } - final SurfaceControl leash = mControl.getLeash(); - if (leash != null) { - final Transaction t = mDisplayContent.getPendingTransaction(); - final Point position = mControl.getSurfacePosition(); - t.setPosition(leash, position.x, position.y); - deferTransactionUntil(t, leash, frameNumber); - } - } - private Point getWindowFrameSurfacePosition() { final Rect frame = mWin.getFrame(); final Point position = new Point(); @@ -281,14 +274,6 @@ class InsetsSourceProvider { return position; } - private void deferTransactionUntil(Transaction t, SurfaceControl leash, long frameNumber) { - if (frameNumber >= 0) { - final SurfaceControl barrier = mWin.getClientViewRootSurface(); - t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber); - t.deferTransactionUntil(leash, barrier, frameNumber); - } - } - /** * @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget) */ @@ -342,15 +327,6 @@ class InsetsSourceProvider { mIsLeashReadyForDispatching = false; final SurfaceControl leash = mAdapter.mCapturedLeash; - final long frameNumber = mFinishSeamlessRotateFrameNumber; - mFinishSeamlessRotateFrameNumber = -1; - if (mWin.mHasSurface && leash != null) { - // We just finished the seamless rotation. We don't want to change the position or the - // window crop of the surface controls (including the leash) until the client finishes - // drawing the new frame of the new orientation. Although we cannot defer the reparent - // operation, it is fine, because reparent won't cause any visual effect. - deferTransactionUntil(t, leash, frameNumber); - } mControlTarget = target; updateVisibility(); mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition); @@ -359,19 +335,14 @@ class InsetsSourceProvider { } void startSeamlessRotation() { - if (!mSeamlessRotating) { - mSeamlessRotating = true; - - // This will revoke the leash and clear the control target. - mWin.cancelAnimation(); - } + if (!mSeamlessRotating) { + mSeamlessRotating = true; + mWin.cancelAnimation(); + } } - void finishSeamlessRotation(boolean timeout) { - if (mSeamlessRotating) { - mSeamlessRotating = false; - mFinishSeamlessRotateFrameNumber = timeout ? -1 : mWin.getFrameNumber(); - } + void finishSeamlessRotation() { + mSeamlessRotating = false; } boolean updateClientVisibility(InsetsControlTarget caller) { @@ -529,7 +500,6 @@ class InsetsSourceProvider { proto.write(CLIENT_VISIBLE, mClientVisible); proto.write(SERVER_VISIBLE, mServerVisible); proto.write(SEAMLESS_ROTATING, mSeamlessRotating); - proto.write(FINISH_SEAMLESS_ROTATE_FRAME_NUMBER, mFinishSeamlessRotateFrameNumber); proto.write(CONTROLLABLE, mControllable); proto.end(token); } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index e02cce4b946a..914e45641b45 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -17,7 +17,9 @@ package com.android.server.wm; 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.res.Configuration.ORIENTATION_LANDSCAPE; import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.RemoteAnimationTarget.MODE_OPENING; import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; @@ -104,7 +106,8 @@ public class RecentsAnimationController implements DeathRecipient { public @interface ReorderMode {} private final WindowManagerService mService; - private final StatusBarManagerInternal mStatusBar; + @VisibleForTesting + final StatusBarManagerInternal mStatusBar; private IRecentsAnimationRunner mRunner; private final RecentsAnimationCallbacks mCallbacks; private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>(); @@ -149,6 +152,7 @@ public class RecentsAnimationController implements DeathRecipient { @VisibleForTesting boolean mShouldAttachNavBarToAppDuringTransition; + private boolean mNavigationBarAttachedToApp; /** * Animates the screenshot of task that used to be controlled by RecentsAnimation. @@ -369,7 +373,17 @@ public class RecentsAnimationController implements DeathRecipient { } @Override - public void detachNavigationBarFromApp() {} + public void detachNavigationBarFromApp(boolean moveHomeToTop) { + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mService.getWindowManagerLock()) { + restoreNavigationBarFromApp(moveHomeToTop); + mService.mWindowPlacerLocked.requestTraversal(); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } }; /** @@ -440,9 +454,7 @@ public class RecentsAnimationController implements DeathRecipient { return; } - if (mShouldAttachNavBarToAppDuringTransition) { - attachNavBarToApp(); - } + attachNavigationBarToApp(); // Adjust the wallpaper visibility for the showing target activity ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, @@ -577,32 +589,52 @@ public class RecentsAnimationController implements DeathRecipient { } } + boolean isNavigationBarAttachedToApp() { + return mNavigationBarAttachedToApp; + } + @VisibleForTesting - WindowToken getNavigationBarWindowToken() { - WindowState navBar = mDisplayContent.getDisplayPolicy().getNavigationBar(); - if (navBar != null) { - return navBar.mToken; - } - return null; + WindowState getNavigationBarWindow() { + return mDisplayContent.getDisplayPolicy().getNavigationBar(); } - private void attachNavBarToApp() { + private void attachNavigationBarToApp() { + if (!mShouldAttachNavBarToAppDuringTransition + // Skip the case where the nav bar is controlled by fixed rotation. + || mDisplayContent.getFixedRotationAnimationController() != null) { + return; + } ActivityRecord topActivity = null; + boolean shouldTranslateNavBar = false; + final boolean isDisplayLandscape = + mDisplayContent.getConfiguration().orientation == ORIENTATION_LANDSCAPE; for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { final TaskAnimationAdapter adapter = mPendingAnimations.get(i); final Task task = adapter.mTask; - if (!task.isHomeOrRecentsRootTask()) { - topActivity = task.getTopVisibleActivity(); - break; + final boolean isSplitScreenSecondary = + task.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; + if (task.isHomeOrRecentsRootTask() + // TODO(b/178449492): Will need to update for the new split screen mode once + // it's ready. + // Skip if the task is the secondary split screen and in landscape. + || (isSplitScreenSecondary && isDisplayLandscape)) { + continue; } + shouldTranslateNavBar = isSplitScreenSecondary; + topActivity = task.getTopVisibleActivity(); + break; } - final WindowToken navToken = getNavigationBarWindowToken(); - if (topActivity == null || navToken == null) { + + final WindowState navWindow = getNavigationBarWindow(); + if (topActivity == null || navWindow == null || navWindow.mToken == null) { return; } - - final SurfaceControl.Transaction t = navToken.getPendingTransaction(); - final SurfaceControl navSurfaceControl = navToken.getSurfaceControl(); + mNavigationBarAttachedToApp = true; + final SurfaceControl.Transaction t = navWindow.mToken.getPendingTransaction(); + final SurfaceControl navSurfaceControl = navWindow.mToken.getSurfaceControl(); + if (shouldTranslateNavBar) { + navWindow.setSurfaceTranslationY(-topActivity.getBounds().top); + } t.reparent(navSurfaceControl, topActivity.getSurfaceControl()); t.show(navSurfaceControl); @@ -613,17 +645,33 @@ public class RecentsAnimationController implements DeathRecipient { // Place the nav bar on top of anything else in the top activity. t.setLayer(navSurfaceControl, Integer.MAX_VALUE); } + if (mStatusBar != null) { + mStatusBar.setNavigationBarLumaSamplingEnabled(mDisplayId, false); + } } - private void restoreNavBarFromApp(boolean animate) { - // Reparent the SurfaceControl of nav bar token back. - final WindowToken navToken = getNavigationBarWindowToken(); - final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction(); - if (navToken != null) { - final WindowContainer parent = navToken.getParent(); - t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl()); + private void restoreNavigationBarFromApp(boolean animate) { + if (!mNavigationBarAttachedToApp) { + return; + } + if (mStatusBar != null) { + mStatusBar.setNavigationBarLumaSamplingEnabled(mDisplayId, true); } + final WindowState navWindow = getNavigationBarWindow(); + if (navWindow == null) { + return; + } + navWindow.setSurfaceTranslationY(0); + + if (navWindow.mToken == null) { + return; + } + final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction(); + final WindowContainer parent = navWindow.mToken.getParent(); + // Reparent the SurfaceControl of nav bar token back. + t.reparent(navWindow.mToken.getSurfaceControl(), parent.getSurfaceControl()); + if (animate) { // Run fade-in animation to show navigation bar back to bottom of the display. final NavBarFadeAnimationController controller = @@ -852,9 +900,7 @@ public class RecentsAnimationController implements DeathRecipient { removeWallpaperAnimation(wallpaperAdapter); } - if (mShouldAttachNavBarToAppDuringTransition) { - restoreNavBarFromApp(reorderMode == REORDER_MOVE_TO_TOP); - } + restoreNavigationBarFromApp(reorderMode == REORDER_MOVE_TO_TOP); // Clear any pending failsafe runnables mService.mH.removeCallbacks(mFailsafeRunnable); diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 42cb96f65738..6fc585e473a9 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -104,11 +104,11 @@ class RemoteAnimationController implements DeathRecipient { */ void goodToGo(@WindowManager.TransitionOldType int transit) { ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo()"); - if (mPendingAnimations.isEmpty() || mCanceled) { + if (mCanceled) { ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, - "goodToGo(): Animation finished already, canceled=%s mPendingAnimations=%d", - mCanceled, mPendingAnimations.size()); + "goodToGo(): Animation canceled already"); onAnimationFinished(); + invokeAnimationCancelled(); return; } @@ -120,8 +120,11 @@ class RemoteAnimationController implements DeathRecipient { // Create the app targets final RemoteAnimationTarget[] appTargets = createAppAnimations(); if (appTargets.length == 0) { - ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo(): No apps to animate"); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, + "goodToGo(): No apps to animate, mPendingAnimations=%d", + mPendingAnimations.size()); onAnimationFinished(); + invokeAnimationCancelled(); return; } diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java index 3d305e4d852d..1e8b8a5bb576 100644 --- a/services/core/java/com/android/server/wm/SeamlessRotator.java +++ b/services/core/java/com/android/server/wm/SeamlessRotator.java @@ -35,9 +35,6 @@ import java.io.StringWriter; * Helper class for seamless rotation. * * Works by transforming the {@link WindowState} back into the old display rotation. - * - * Uses {@link Transaction#deferTransactionUntil(SurfaceControl, IBinder, long)} instead of - * latching on the buffer size to allow for seamless 180 degree rotations. */ public class SeamlessRotator { @@ -103,22 +100,7 @@ public class SeamlessRotator { * Removing the transform and the result of the {@link WindowState} layout are both tied to the * {@link WindowState} next frame, such that they apply at the same time the client draws the * window in the new orientation. - * - * In the case of a rotation timeout, we want to remove the transform immediately and not defer - * it. */ - public void finish(WindowState win, boolean timeout) { - final Transaction t = win.getPendingTransaction(); - finish(t, win); - if (win.mWinAnimator.mSurfaceController != null && !timeout) { - t.deferTransactionUntil(win.mSurfaceControl, - win.getClientViewRootSurface(), win.getFrameNumber()); - t.deferTransactionUntil(win.mWinAnimator.mSurfaceController.mSurfaceControl, - win.getClientViewRootSurface(), win.getFrameNumber()); - } - } - - /** Removes the transform and restore to the original last position. */ void finish(Transaction t, WindowContainer win) { mTransform.reset(); t.setMatrix(win.mSurfaceControl, mTransform, mFloat9); diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java index ef4a40f4837c..6c4613526e88 100644 --- a/services/core/java/com/android/server/wm/StartingSurfaceController.java +++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java @@ -40,9 +40,8 @@ public class StartingSurfaceController { private static final String TAG = TAG_WITH_CLASS_NAME ? StartingSurfaceController.class.getSimpleName() : TAG_WM; /** Set to {@code true} to enable shell starting surface drawer. */ - private static final boolean DEBUG_ENABLE_SHELL_DRAWER = - SystemProperties.getBoolean("persist.debug.shell_starting_surface", false); - + static final boolean DEBUG_ENABLE_SHELL_DRAWER = + SystemProperties.getBoolean("persist.debug.shell_starting_surface", true); private final WindowManagerService mService; public StartingSurfaceController(WindowManagerService wm) { @@ -139,8 +138,9 @@ public class StartingSurfaceController { } @Override - public void remove() { - mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask); + public void remove(boolean animate) { + mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask, + animate); } } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index d992a4591a22..a4b4726fe070 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -4135,6 +4135,8 @@ class Task extends WindowContainer<WindowContainer> { final StartingWindowInfo info = new StartingWindowInfo(); info.taskInfo = getTaskInfo(); + info.isKeyguardOccluded = + mAtmService.mKeyguardController.isDisplayOccluded(DEFAULT_DISPLAY); final ActivityRecord topActivity = getTopMostActivity(); if (topActivity != null) { info.startingWindowTypeParameter = @@ -5245,17 +5247,29 @@ class Task extends WindowContainer<WindowContainer> { if (mForceHiddenFlags == newFlags) { return false; } + final boolean wasHidden = isForceHidden(); + final boolean wasVisible = isVisible(); mForceHiddenFlags = newFlags; - if (wasHidden != isForceHidden() && isTopActivityFocusable()) { - // The change in force-hidden state will change visibility without triggering a root - // task order change, so we should reset the preferred top focusable root task to ensure - // it's not used if a new activity is started from this task. - getDisplayArea().resetPreferredTopFocusableRootTaskIfNeeded(this); + final boolean nowHidden = isForceHidden(); + if (wasHidden != nowHidden) { + final String reason = "setForceHidden"; + if (wasVisible && nowHidden) { + // Move this visible task to back when the task is forced hidden + moveToBack(reason, null); + } else if (isAlwaysOnTop()) { + // Move this always-on-top task to front when no longer hidden + moveToFront(reason); + } } return true; } + @Override + public boolean isAlwaysOnTop() { + return !isForceHidden() && super.isAlwaysOnTop(); + } + /** * Returns whether this task is currently forced to be hidden for any reason. */ @@ -7482,17 +7496,22 @@ class Task extends WindowContainer<WindowContainer> { } public void setAlwaysOnTop(boolean alwaysOnTop) { - if (isAlwaysOnTop() == alwaysOnTop) { + // {@link #isAwaysonTop} overrides the original behavior which also evaluates if this + // task is force hidden, so super.isAlwaysOnTop() is used here to see whether the + // alwaysOnTop attributes should be updated. + if (super.isAlwaysOnTop() == alwaysOnTop) { return; } super.setAlwaysOnTop(alwaysOnTop); - final TaskDisplayArea taskDisplayArea = getDisplayArea(); // positionChildAtTop() must be called even when always on top gets turned off because we // need to make sure that the root task is moved from among always on top windows to // below other always on top windows. Since the position the root task should be inserted // into is calculated properly in {@link DisplayContent#getTopInsertPosition()} in both // cases, we can just request that the root task is put at top here. - taskDisplayArea.positionChildAt(POSITION_TOP, this, false /* includingParents */); + // Don't bother moving task to top if this task is force hidden and invisible to user. + if (!isForceHidden()) { + getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */); + } } void dismissPip() { diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index ed92fd08bef5..91aa48effe84 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -393,7 +393,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { final boolean moveToBottom = position <= 0; final int oldPosition = mChildren.indexOf(child); - if (child.getWindowConfiguration().isAlwaysOnTop() && !moveToTop) { + if (child.isAlwaysOnTop() && !moveToTop) { // This root task is always-on-top, override the default behavior. Slog.w(TAG_WM, "Ignoring move of always-on-top root task=" + this + " to bottom"); @@ -974,14 +974,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { onRootTaskOrderChanged(rootTask); } - /** Reset the mPreferredTopFocusableRootTask if it is or below the given task. */ - void resetPreferredTopFocusableRootTaskIfNeeded(Task task) { - if (mPreferredTopFocusableRootTask != null - && mPreferredTopFocusableRootTask.compareTo(task) <= 0) { - mPreferredTopFocusableRootTask = null; - } - } - /** * Moves/reparents `task` to the back of whatever container the root home task is in. This is * for when we just want to move a task to "the back" vs. a specific place. The primary use-case diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index fc6db61bdbcd..385dc79567fa 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -32,6 +32,7 @@ import android.app.WindowConfiguration; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ParceledListSlice; +import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; @@ -131,10 +132,28 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { }); } - void removeStartingWindow(Task task) { + void removeStartingWindow(Task task, boolean prepareAnimation) { mDeferTaskOrgCallbacksConsumer.accept(() -> { + SurfaceControl firstWindowLeash = null; + Rect mainFrame = null; + // TODO enable shift up animation once we fix flicker test +// final boolean playShiftUpAnimation = !task.inMultiWindowMode(); +// if (prepareAnimation && playShiftUpAnimation) { +// final ActivityRecord topActivity = task.topActivityWithStartingWindow(); +// if (topActivity != null) { +// final WindowState mainWindow = +// topActivity.findMainWindow(false/* includeStartingApp */); +// if (mainWindow != null) { + // TODO create proper leash instead of the copied SC +// firstWindowLeash = new SurfaceControl(mainWindow.getSurfaceControl(), +// "TaskOrganizerController.removeStartingWindow"); +// mainFrame = mainWindow.getRelativeFrame(); +// } +// } +// } try { - mTaskOrganizer.removeStartingWindow(task.mTaskId); + mTaskOrganizer.removeStartingWindow(task.mTaskId, firstWindowLeash, mainFrame, + prepareAnimation); } catch (RemoteException e) { Slog.e(TAG, "Exception sending onStartTaskFinished callback", e); } @@ -249,8 +268,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { mOrganizer.addStartingWindow(t, appToken, launchTheme); } - void removeStartingWindow(Task t) { - mOrganizer.removeStartingWindow(t); + void removeStartingWindow(Task t, boolean prepareAnimation) { + mOrganizer.removeStartingWindow(t, prepareAnimation); } void copySplashScreenView(Task t) { @@ -495,14 +514,14 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { return true; } - void removeStartingWindow(Task task) { + void removeStartingWindow(Task task, boolean prepareAnimation) { final Task rootTask = task.getRootTask(); if (rootTask == null || rootTask.mTaskOrganizer == null) { return; } final TaskOrganizerState state = mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder()); - state.removeStartingWindow(task); + state.removeStartingWindow(task, prepareAnimation); } boolean copySplashScreenView(Task task) { diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index 9d35c25fc546..525420e045b5 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -188,7 +188,8 @@ class TaskPositioningController { transferFocusFromWin = displayContent.mCurrentFocus; } if (!mInputManager.transferTouchFocus( - transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel)) { + transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel, + false /* isDragDrop */)) { Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus"); cleanUpTaskPositioner(); return false; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index b810de99ee10..8915eba3d509 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -37,6 +37,7 @@ import android.os.Handler; import android.util.ArraySet; import android.util.Pair; import android.util.Slog; +import android.view.Display; import android.view.InsetsState; import android.view.SurfaceControl; import android.view.ThreadedRenderer; @@ -624,7 +625,7 @@ class TaskSnapshotController { /** * Called when screen is being turned off. */ - void screenTurningOff(ScreenOffListener listener) { + void screenTurningOff(int displayId, ScreenOffListener listener) { if (shouldDisableSnapshots()) { listener.onScreenOff(); return; @@ -635,7 +636,7 @@ class TaskSnapshotController { try { synchronized (mService.mGlobalLock) { mTmpTasks.clear(); - mService.mRoot.forAllTasks(task -> { + mService.mRoot.getDisplayContent(displayId).forAllTasks(task -> { // Since RecentsAnimation will handle task snapshot while switching apps // with the best capture timing (e.g. IME window capture), No need // additional task capture while task is controlled by RecentsAnimation. @@ -645,7 +646,7 @@ class TaskSnapshotController { }); // Allow taking snapshot of home when turning screen off to reduce the delay of // waking from secure lock to home. - final boolean allowSnapshotHome = + final boolean allowSnapshotHome = displayId == Display.DEFAULT_DISPLAY && mService.mPolicy.isKeyguardSecure(mService.mCurrentUserId); snapshotTasks(mTmpTasks, allowSnapshotHome); } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index 07610ab6d546..79a6bd7dcd2c 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -281,13 +281,14 @@ class TaskSnapshotSurface implements StartingSurface { } @Override - public void remove() { + public void remove(boolean animate) { synchronized (mService.mGlobalLock) { final long now = SystemClock.uptimeMillis(); if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS // Show the latest content as soon as possible for unlocking to home. && mActivityType != ACTIVITY_TYPE_HOME) { - mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS); + mHandler.postAtTime(() -> remove(false /* prepareAnimation */), + mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS); ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Defer removing snapshot surface in %dms", (now - mShownTime)); @@ -517,7 +518,7 @@ class TaskSnapshotSurface implements StartingSurface { // The orientation of the screen is changing. We better remove the snapshot ASAP as // we are going to wait on the new window in any case to unfreeze the screen, and // the starting window is not needed anymore. - sHandler.post(mOuter::remove); + sHandler.post(() -> mOuter.remove(false /* prepareAnimation */)); } if (reportDraw) { sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget(); diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java index 9245f8c3efe5..ffd6d21c1026 100644 --- a/services/core/java/com/android/server/wm/WindowFrames.java +++ b/services/core/java/com/android/server/wm/WindowFrames.java @@ -113,7 +113,7 @@ public class WindowFrames { } /** - * @return true if the width or height has changed since last reported to the client. + * @return true if the width or height has changed since last updating resizing window. */ boolean didFrameSizeChange() { return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height()); @@ -135,6 +135,13 @@ public class WindowFrames { } /** + * @return true if the width or height has changed since last reported to the client. + */ + boolean isFrameSizeChangeReported() { + return mFrameSizeChanged || didFrameSizeChange(); + } + + /** * Resets the size changed flags so they're all set to false again. This should be called * after the frames are reported to client. */ diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 7450782364f4..53ebfb2c6e0e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -221,7 +221,8 @@ public abstract class WindowManagerInternal { DragState state, Display display, InputManagerService service, InputChannel source) { state.register(display); - return service.transferTouchFocus(source, state.getInputChannel()); + return service.transferTouchFocus(source, state.getInputChannel(), + true /* isDragDrop */); } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 6f853c795525..b95674e511d5 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -273,7 +273,6 @@ import android.window.TaskSnapshot; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.os.BackgroundThread; import com.android.internal.os.IResultReceiver; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; @@ -367,9 +366,6 @@ public class WindowManagerService extends IWindowManager.Stub /** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */ static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000; - /** Amount of time (in milliseconds) to delay before declaring a seamless rotation timeout. */ - static final int SEAMLESS_ROTATION_TIMEOUT_DURATION = 2000; - /** Amount of time (in milliseconds) to delay before declaring a window replacement timeout. */ static final int WINDOW_REPLACEMENT_TIMEOUT_DURATION = 2000; @@ -529,14 +525,6 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) { - // Bugreport dumps the trace 2x, 1x as proto and 1x as text. Save file to disk only 1x. - if (asProto && mWindowTracing.isEnabled()) { - mWindowTracing.stopTrace(null, false /* writeToFile */); - BackgroundThread.getHandler().post(() -> { - mWindowTracing.writeTraceToFile(); - mWindowTracing.startTrace(null); - }); - } doDump(fd, pw, new String[] {"-a"}, asProto); } @@ -2245,16 +2233,9 @@ public class WindowManagerService extends IWindowManager.Stub win.setFrameNumber(frameNumber); final DisplayContent dc = win.getDisplayContent(); - if (!dc.mWaitingForConfig) { - win.finishSeamlessRotation(false /* timeout */); - } - - if (win.mPendingPositionChanged != null) { - win.mPendingPositionChanged.updateLeashPosition(frameNumber); - win.mPendingPositionChanged = null; - } if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE) { + win.prepareDrawHandlers(); result |= RELAYOUT_RES_BLAST_SYNC; } @@ -2999,8 +2980,8 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void screenTurningOff(ScreenOffListener listener) { - mTaskSnapshotController.screenTurningOff(listener); + public void screenTurningOff(int displayId, ScreenOffListener listener) { + mTaskSnapshotController.screenTurningOff(displayId, listener); } @Override @@ -5095,7 +5076,6 @@ public class WindowManagerService extends IWindowManager.Stub public static final int UPDATE_ANIMATION_SCALE = 51; public static final int WINDOW_HIDE_TIMEOUT = 52; - public static final int SEAMLESS_ROTATION_TIMEOUT = 54; public static final int RESTORE_POINTER_ICON = 55; public static final int SET_HAS_OVERLAY_UI = 58; public static final int ANIMATION_FAILSAFE = 60; @@ -5378,13 +5358,6 @@ public class WindowManagerService extends IWindowManager.Stub } break; } - case SEAMLESS_ROTATION_TIMEOUT: { - final DisplayContent displayContent = (DisplayContent) msg.obj; - synchronized (mGlobalLock) { - displayContent.getDisplayRotation().onSeamlessRotationTimeout(); - } - break; - } case SET_HAS_OVERLAY_UI: { mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1); break; @@ -5702,6 +5675,11 @@ public class WindowManagerService extends IWindowManager.Stub mBlurController.unregisterCrossWindowBlurEnabledListener(listener); } + @Override + public void setForceCrossWindowBlurDisabled(boolean disable) { + mBlurController.setForceCrossWindowBlurDisabled(disable); + } + // ------------------------------------------------------------- // Internals // ------------------------------------------------------------- diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index d9b879fdf8dc..7ebc1cc6d5c1 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -168,8 +168,8 @@ import static com.android.server.wm.WindowStateProto.FINISHED_SEAMLESS_ROTATION_ import static com.android.server.wm.WindowStateProto.FORCE_SEAMLESS_ROTATION; import static com.android.server.wm.WindowStateProto.GIVEN_CONTENT_INSETS; import static com.android.server.wm.WindowStateProto.GLOBAL_SCALE; +import static com.android.server.wm.WindowStateProto.HAS_COMPAT_SCALE; import static com.android.server.wm.WindowStateProto.HAS_SURFACE; -import static com.android.server.wm.WindowStateProto.IN_SIZE_COMPAT_MODE; import static com.android.server.wm.WindowStateProto.IS_ON_SCREEN; import static com.android.server.wm.WindowStateProto.IS_READY_FOR_DISPLAY; import static com.android.server.wm.WindowStateProto.IS_VISIBLE; @@ -261,6 +261,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.function.Consumer; import java.util.function.Predicate; /** A window in the window manager. */ @@ -725,8 +726,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ private InsetsState mFrozenInsetsState; - @Nullable InsetsSourceProvider mPendingPositionChanged; - private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f; private KeyInterceptionInfo mKeyInterceptionInfo; @@ -749,6 +748,42 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private final WindowProcessController mWpcForDisplayAreaConfigChanges; /** + * We split the draw handlers in to a "pending" and "ready" list, in order to solve + * sequencing problems. Think of it this way, let's say I update a windows orientation + * (in configuration), and then I call applyWithNextDraw. What I'm hoping for is to + * apply with the draw that contains the orientation change. However, since the client + * can call finishDrawing at any time, it could be about to call a previous call to + * finishDrawing (or maybe its already called it, we just haven't handled it). Since this + * frame was already completed it had no time to include the orientation change we made. + * To solve this problem we accumulate draw handlers in mPendingDrawHandlers, and then force + * the client to call relayout. Only the frame post relayout will contain the configuration + * change since the window has to relayout), and so in relayout we drain mPendingDrawHandlers + * into mReadyDrawHandlers. Finally once we get to finishDrawing we know everything in + * mReadyDrawHandlers corresponds to state which was observed by the client and we can + * invoke the consumers. + */ + private final List<Consumer<SurfaceControl.Transaction>> mPendingDrawHandlers + = new ArrayList<>(); + private final List<Consumer<SurfaceControl.Transaction>> mReadyDrawHandlers + = new ArrayList<>(); + + private final Consumer<SurfaceControl.Transaction> mSeamlessRotationFinishedConsumer = t -> { + finishSeamlessRotation(t); + updateSurfacePosition(t); + }; + + private final Consumer<SurfaceControl.Transaction> mSetSurfacePositionConsumer = t -> { + if (mSurfaceControl != null && mSurfaceControl.isValid()) { + t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y); + } + }; + + /** + * @see #setSurfaceTranslationY(int) + */ + private int mSurfaceTranslationY; + + /** * Returns the visibility of the given {@link InternalInsetsType type} requested by the client. * * @param type the given {@link InternalInsetsType type}. @@ -831,19 +866,27 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mPendingSeamlessRotate.unrotate(transaction, this); getDisplayContent().getDisplayRotation().markForSeamlessRotation(this, true /* seamlesslyRotated */); + applyWithNextDraw(mSeamlessRotationFinishedConsumer); } } - void finishSeamlessRotation(boolean timeout) { - if (mPendingSeamlessRotate != null) { - mPendingSeamlessRotate.finish(this, timeout); - mFinishSeamlessRotateFrameNumber = getFrameNumber(); - mPendingSeamlessRotate = null; - getDisplayContent().getDisplayRotation().markForSeamlessRotation(this, - false /* seamlesslyRotated */); - if (mControllableInsetProvider != null) { - mControllableInsetProvider.finishSeamlessRotation(timeout); - } + void cancelSeamlessRotation() { + finishSeamlessRotation(getPendingTransaction()); + } + + void finishSeamlessRotation(SurfaceControl.Transaction t) { + if (mPendingSeamlessRotate == null) { + return; + } + + mPendingSeamlessRotate.finish(t, this); + mFinishSeamlessRotateFrameNumber = getFrameNumber(); + mPendingSeamlessRotate = null; + + getDisplayContent().getDisplayRotation().markForSeamlessRotation(this, + false /* seamlesslyRotated */); + if (mControllableInsetProvider != null) { + mControllableInsetProvider.finishSeamlessRotation(); } } @@ -1050,18 +1093,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * scaling override set. * @see CompatModePackages#getCompatScale * @see android.content.res.CompatibilityInfo#supportsScreen - * @see ActivityRecord#inSizeCompatMode() + * @see ActivityRecord#hasSizeCompatBounds() */ - boolean inSizeCompatMode() { - return mOverrideScale != 1f || inSizeCompatMode(mAttrs, mActivityRecord); + boolean hasCompatScale() { + return mOverrideScale != 1f || hasCompatScale(mAttrs, mActivityRecord); } /** * @return {@code true} if the application runs in size compatibility mode. * @see android.content.res.CompatibilityInfo#supportsScreen - * @see ActivityRecord#inSizeCompatMode() + * @see ActivityRecord#hasSizeCompatBounds() */ - static boolean inSizeCompatMode(WindowManager.LayoutParams attrs, WindowToken windowToken) { + static boolean hasCompatScale(WindowManager.LayoutParams attrs, WindowToken windowToken) { return (attrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0 || (windowToken != null && windowToken.hasSizeCompatBounds() // Exclude starting window because it is not displayed by the application. @@ -1266,7 +1309,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP windowFrames.offsetFrames(-layoutXDiff, -layoutYDiff); windowFrames.mCompatFrame.set(windowFrames.mFrame); - if (inSizeCompatMode()) { + if (hasCompatScale()) { // Also the scaled frame that we report to the app needs to be // adjusted to be in its coordinate space. windowFrames.mCompatFrame.scale(mInvGlobalScale); @@ -1538,7 +1581,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ InsetsState getCompatInsetsState() { InsetsState state = getInsetsState(); - if (inSizeCompatMode()) { + if (hasCompatScale()) { state = new InsetsState(state, true); state.scale(mInvGlobalScale); } @@ -1676,7 +1719,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } void prelayout() { - if (inSizeCompatMode()) { + if (hasCompatScale()) { if (mOverrideScale != 1f) { mGlobalScale = mToken.hasSizeCompatBounds() ? mToken.getSizeCompatScale() * mOverrideScale @@ -2090,6 +2133,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP : getTask().getWindowConfiguration().hasMovementAnimations(); if (mToken.okToAnimate() && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0 + && !mWindowFrames.didFrameSizeChange() + && !surfaceInsetsChanging() && !isDragResizing() && hasMovementAnimation && !mWinAnimator.mLastHidden @@ -3590,7 +3635,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP void fillClientWindowFrames(ClientWindowFrames outFrames) { outFrames.frame.set(mWindowFrames.mCompatFrame); outFrames.displayFrame.set(mWindowFrames.mDisplayFrame); - if (mInvGlobalScale != 1.0f && inSizeCompatMode()) { + if (mInvGlobalScale != 1.0f && hasCompatScale()) { outFrames.displayFrame.scale(mInvGlobalScale); } @@ -3990,7 +4035,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP proto.write(PENDING_SEAMLESS_ROTATION, mPendingSeamlessRotate != null); proto.write(FINISHED_SEAMLESS_ROTATION_FRAME, mFinishSeamlessRotateFrameNumber); proto.write(FORCE_SEAMLESS_ROTATION, mForceSeamlesslyRotate); - proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode()); + proto.write(HAS_COMPAT_SCALE, hasCompatScale()); proto.write(GLOBAL_SCALE, mGlobalScale); proto.end(token); } @@ -4092,7 +4137,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP pw.println(prefix + "mHasSurface=" + mHasSurface + " isReadyForDisplay()=" + isReadyForDisplay() + " mWindowRemovalAllowed=" + mWindowRemovalAllowed); - if (inSizeCompatMode()) { + if (hasCompatScale()) { pw.println(prefix + "mCompatFrame=" + mWindowFrames.mCompatFrame.toShortString(sTmpSB)); } if (dumpAll) { @@ -4215,18 +4260,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP float x, y; int w,h; - final boolean inSizeCompatMode = inSizeCompatMode(); + final boolean hasCompatScale = hasCompatScale(); if ((mAttrs.flags & FLAG_SCALED) != 0) { if (mAttrs.width < 0) { w = pw; - } else if (inSizeCompatMode) { + } else if (hasCompatScale) { w = (int)(mAttrs.width * mGlobalScale + .5f); } else { w = mAttrs.width; } if (mAttrs.height < 0) { h = ph; - } else if (inSizeCompatMode) { + } else if (hasCompatScale) { h = (int)(mAttrs.height * mGlobalScale + .5f); } else { h = mAttrs.height; @@ -4234,21 +4279,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } else { if (mAttrs.width == MATCH_PARENT) { w = pw; - } else if (inSizeCompatMode) { + } else if (hasCompatScale) { w = (int)(mRequestedWidth * mGlobalScale + .5f); } else { w = mRequestedWidth; } if (mAttrs.height == MATCH_PARENT) { h = ph; - } else if (inSizeCompatMode) { + } else if (hasCompatScale) { h = (int)(mRequestedHeight * mGlobalScale + .5f); } else { h = mRequestedHeight; } } - if (inSizeCompatMode) { + if (hasCompatScale) { x = mAttrs.x * mGlobalScale; y = mAttrs.y * mGlobalScale; } else { @@ -4276,7 +4321,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // We need to make sure we update the CompatFrame as it is used for // cropping decisions, etc, on systems where we lack a decor layer. windowFrames.mCompatFrame.set(windowFrames.mFrame); - if (inSizeCompatMode) { + if (hasCompatScale) { // See comparable block in computeFrameLw. windowFrames.mCompatFrame.scale(mInvGlobalScale); } @@ -4394,7 +4439,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP float translateToWindowX(float x) { float winX = x - mWindowFrames.mFrame.left; - if (inSizeCompatMode()) { + if (hasCompatScale()) { winX *= mGlobalScale; } return winX; @@ -4402,7 +4447,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP float translateToWindowY(float y) { float winY = y - mWindowFrames.mFrame.top; - if (inSizeCompatMode()) { + if (hasCompatScale()) { winY *= mGlobalScale; } return winY; @@ -5279,13 +5324,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // prior to the rotation. if (!mSurfaceAnimator.hasLeash() && mPendingSeamlessRotate == null && !mLastSurfacePosition.equals(mSurfacePosition)) { - t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y); + final boolean frameSizeChanged = mWindowFrames.isFrameSizeChangeReported(); + final boolean surfaceInsetsChanged = surfaceInsetsChanging(); + final boolean surfaceSizeChanged = frameSizeChanged || surfaceInsetsChanged; mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y); - if (surfaceInsetsChanging() && mWinAnimator.hasSurface()) { + if (surfaceInsetsChanged) { mLastSurfaceInsets.set(mAttrs.surfaceInsets); - t.deferTransactionUntil(mSurfaceControl, - mWinAnimator.mSurfaceController.mSurfaceControl, - getFrameNumber()); + } + if (surfaceSizeChanged) { + applyWithNextDraw(mSetSurfacePositionConsumer); + } else { + mSetSurfacePositionConsumer.accept(t); } } } @@ -5324,6 +5373,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Expand for surface insets. See WindowState.expandForSurfaceInsets. transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets); outPoint.offset(-mTmpPoint.x, -mTmpPoint.y); + + outPoint.y += mSurfaceTranslationY; } /** @@ -5331,7 +5382,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * scaled, the insets also need to be scaled for surface position in global coordinate. */ private void transformSurfaceInsetsPosition(Point outPos, Rect surfaceInsets) { - if (!inSizeCompatMode()) { + if (!hasCompatScale()) { outPos.x = surfaceInsets.left; outPos.y = surfaceInsets.top; return; @@ -5684,6 +5735,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP Slog.i(TAG, "finishDrawing of relaunch: " + this + " " + duration + "ms"); mActivityRecord.mRelaunchStartTime = 0; } + + executeDrawHandlers(postDrawTransaction); if (!onSyncFinishedDrawing()) { return mWinAnimator.finishDrawingLocked(postDrawTransaction); } @@ -5698,6 +5751,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } void immediatelyNotifyBlastSync() { + prepareDrawHandlers(); finishDrawing(null); mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this); if (!useBLASTSync()) return; @@ -5777,4 +5831,75 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP outSize.inset(-attrs.surfaceInsets.left, -attrs.surfaceInsets.top, -attrs.surfaceInsets.right, -attrs.surfaceInsets.bottom); } + + /** + * This method is used to control whether we return the BLAST_SYNC flag + * from relayoutWindow calls on this window (triggering the client to redirect + * it's next draw in to a transaction). If we have pending draw handlers, we are + * looking for the client to sync. + * + * See {@link WindowState#mPendingDrawHandlers} + */ + @Override + boolean useBLASTSync() { + return super.useBLASTSync() || (mPendingDrawHandlers.size() != 0); + } + + /** + * Apply the transaction with the next window redraw. A full relayout/finishDrawing + * cycle must occur before completion. This means if you call the function while + * "in relayout", the results may be undefined but at all other times the function + * should sort of transparently work like this: + * 1. Make changes to WM hierarchy (say change app configuration) + * 2. Call apply with next draw. + * 3. After finishDrawing, our consumer will be passed the Transaction + * containing the buffer, and we can merge in additional operations. + * See {@link WindowState#mPendingDrawHandlers} + */ + void applyWithNextDraw(Consumer<SurfaceControl.Transaction> consumer) { + mPendingDrawHandlers.add(consumer); + requestRedrawForSync(); + + mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this, + BLAST_TIMEOUT_DURATION); + } + + /** + * Called from relayout, to indicate the next "finishDrawing" will contain + * all changes applied by the time mPendingDrawHandlers was populated. + * + * See {@link WindowState#mPendingDrawHandlers} + */ + void prepareDrawHandlers() { + mReadyDrawHandlers.addAll(mPendingDrawHandlers); + mPendingDrawHandlers.clear(); + } + + /** + * Drain the draw handlers, called from finishDrawing() + * See {@link WindowState#mPendingDrawHandlers} + */ + boolean executeDrawHandlers(SurfaceControl.Transaction t) { + if (t == null) t = mTmpTransaction; + boolean hadHandlers = false; + for (int i = 0; i < mReadyDrawHandlers.size(); i++) { + mReadyDrawHandlers.get(i).accept(t); + hadHandlers = true; + } + mReadyDrawHandlers.clear(); + mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this); + + t.apply(); + + return hadHandlers; + } + + /** + * Adds an additional translation offset to be applied when positioning the surface. Used to + * correct offsets in specific reparenting situations, e.g. the navigation bar window attached + * on the lower split-screen app. + */ + void setSurfaceTranslationY(int translationY) { + mSurfaceTranslationY = translationY; + } } diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java index e8b8bfce21a3..0bb97f560a1c 100644 --- a/services/core/java/com/android/server/wm/WindowTracing.java +++ b/services/core/java/com/android/server/wm/WindowTracing.java @@ -114,15 +114,6 @@ class WindowTracing { * @param pw Print writer */ void stopTrace(@Nullable PrintWriter pw) { - stopTrace(pw, true /* writeToFile */); - } - - /** - * Stops the trace - * @param pw Print writer - * @param writeToFile If the current buffer should be written to disk or not - */ - void stopTrace(@Nullable PrintWriter pw, boolean writeToFile) { if (IS_USER) { logAndPrintln(pw, "Error: Tracing is not supported on user builds."); return; @@ -135,12 +126,35 @@ class WindowTracing { logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush."); throw new IllegalStateException("tracing enabled while waiting for flush."); } - if (writeToFile) { - writeTraceToFileLocked(); - logAndPrintln(pw, "Trace written to " + mTraceFile + "."); + writeTraceToFileLocked(); + logAndPrintln(pw, "Trace written to " + mTraceFile + "."); + } + ProtoLogImpl.getSingleInstance().stopProtoLog(pw, true); + } + + /** + * Stops the trace and write the current buffer to disk then restart, if it's already running. + * @param pw Print writer + */ + void saveForBugreport(@Nullable PrintWriter pw) { + if (IS_USER) { + logAndPrintln(pw, "Error: Tracing is not supported on user builds."); + return; + } + synchronized (mEnabledLock) { + if (!mEnabled) { + return; } + mEnabled = mEnabledLockFree = false; + logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush."); + writeTraceToFileLocked(); + logAndPrintln(pw, "Trace written to " + mTraceFile + "."); + ProtoLogImpl.getSingleInstance().stopProtoLog(pw, true); + logAndPrintln(pw, "Start tracing to " + mTraceFile + "."); + mBuffer.resetBuffer(); + mEnabled = mEnabledLockFree = true; + ProtoLogImpl.getSingleInstance().startProtoLog(pw); } - ProtoLogImpl.getSingleInstance().stopProtoLog(pw, writeToFile); } private void setLogLevel(@WindowTraceLogLevel int logLevel, PrintWriter pw) { @@ -188,6 +202,9 @@ class WindowTracing { case "stop": stopTrace(pw); return 0; + case "save-for-bugreport": + saveForBugreport(pw); + return 0; case "status": logAndPrintln(pw, getStatus()); return 0; @@ -230,6 +247,7 @@ class WindowTracing { pw.println("Window manager trace options:"); pw.println(" start: Start logging"); pw.println(" stop: Stop logging"); + pw.println(" save-for-bugreport: Save logging data to file if it's running."); pw.println(" frame: Log trace once per frame"); pw.println(" transaction: Log each transaction"); pw.println(" size: Set the maximum log size (in KB)"); @@ -316,19 +334,6 @@ class WindowTracing { } } - /** - * Writes the trace buffer to new file for the bugreport. - * - * This method is synchronized with {@code #startTrace(PrintWriter)} and - * {@link #stopTrace(PrintWriter)}. - */ - void writeTraceToFile() { - synchronized (mEnabledLock) { - writeTraceToFileLocked(); - } - ProtoLogImpl.getSingleInstance().writeProtoLogToFile(); - } - private void logAndPrintln(@Nullable PrintWriter pw, String msg) { Log.i(TAG, msg); if (pw != null) { diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 29bce792fe30..0a02a86e71a6 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -49,7 +49,6 @@ cc_library_static { "com_android_server_net_NetworkStatsService.cpp", "com_android_server_power_PowerManagerService.cpp", "com_android_server_powerstats_PowerStatsService.cpp", - "com_android_server_security_VerityUtils.cpp", "com_android_server_SerialService.cpp", "com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp", "com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp", diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 10705af9ac38..be06d0395499 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1783,8 +1783,9 @@ static void nativeSetSystemUiLightsOut(JNIEnv* /* env */, jclass /* clazz */, jl im->setSystemUiLightsOut(lightsOut); } -static jboolean nativeTransferTouchFocus(JNIEnv* env, - jclass /* clazz */, jlong ptr, jobject fromChannelTokenObj, jobject toChannelTokenObj) { +static jboolean nativeTransferTouchFocus(JNIEnv* env, jclass /* clazz */, jlong ptr, + jobject fromChannelTokenObj, jobject toChannelTokenObj, + jboolean isDragDrop) { if (fromChannelTokenObj == nullptr || toChannelTokenObj == nullptr) { return JNI_FALSE; } @@ -1793,8 +1794,8 @@ static jboolean nativeTransferTouchFocus(JNIEnv* env, sp<IBinder> toChannelToken = ibinderForJavaObject(env, toChannelTokenObj); NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); - if (im->getInputManager()->getDispatcher()->transferTouchFocus( - fromChannelToken, toChannelToken)) { + if (im->getInputManager()->getDispatcher()->transferTouchFocus(fromChannelToken, toChannelToken, + isDragDrop)) { return JNI_TRUE; } else { return JNI_FALSE; @@ -2267,7 +2268,7 @@ static const JNINativeMethod gInputManagerMethods[] = { (void*)nativeRequestPointerCapture}, {"nativeSetInputDispatchMode", "(JZZ)V", (void*)nativeSetInputDispatchMode}, {"nativeSetSystemUiLightsOut", "(JZ)V", (void*)nativeSetSystemUiLightsOut}, - {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)Z", + {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;Z)Z", (void*)nativeTransferTouchFocus}, {"nativeSetPointerSpeed", "(JI)V", (void*)nativeSetPointerSpeed}, {"nativeSetShowTouches", "(JZ)V", (void*)nativeSetShowTouches}, diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 1815f0cd44c9..03a01523b8e2 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -52,7 +52,6 @@ int register_android_server_SyntheticPasswordManager(JNIEnv* env); int register_android_hardware_display_DisplayViewport(JNIEnv* env); int register_android_server_net_NetworkStatsFactory(JNIEnv* env); int register_android_server_net_NetworkStatsService(JNIEnv* env); -int register_android_server_security_VerityUtils(JNIEnv* env); int register_android_server_am_CachedAppOptimizer(JNIEnv* env); int register_android_server_am_LowMemDetector(JNIEnv* env); int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(JNIEnv* env); @@ -106,7 +105,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_hardware_display_DisplayViewport(env); register_android_server_net_NetworkStatsFactory(env); register_android_server_net_NetworkStatsService(env); - register_android_server_security_VerityUtils(env); register_android_server_am_CachedAppOptimizer(env); register_android_server_am_LowMemDetector(env); register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(env); diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp index 6a8f6d419786..d43cf3f59170 100644 --- a/services/core/xsd/Android.bp +++ b/services/core/xsd/Android.bp @@ -45,13 +45,6 @@ xsd_config { } xsd_config { - name: "cec-config", - srcs: ["cec-config/cec-config.xsd"], - api_dir: "cec-config/schema", - package_name: "com.android.server.hdmi.cec.config", -} - -xsd_config { name: "device-state-config", srcs: ["device-state-config/device-state-config.xsd"], api_dir: "device-state-config/schema", diff --git a/services/core/xsd/cec-config/cec-config.xsd b/services/core/xsd/cec-config/cec-config.xsd deleted file mode 100644 index b59c93cce332..000000000000 --- a/services/core/xsd/cec-config/cec-config.xsd +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<xs:schema version="2.0" - elementFormDefault="qualified" - attributeFormDefault="unqualified" - xmlns:xs="http://www.w3.org/2001/XMLSchema"> - <xs:element name="cec-settings"> - <xs:complexType> - <xs:sequence> - <xs:element name="setting" type="setting" minOccurs="0" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - </xs:element> - <xs:complexType name="setting"> - <xs:attribute name="name" type="xs:string"/> - <xs:attribute name="value-type" type="xs:string"/> - <xs:attribute name="user-configurable" type="xs:boolean"/> - <xs:element name="allowed-values" type="value-list" minOccurs="1" maxOccurs="1"/> - <xs:element name="default-value" type="value" minOccurs="1" maxOccurs="1"/> - </xs:complexType> - <xs:complexType name="value-list"> - <xs:sequence> - <xs:element name="value" type="value" minOccurs="1" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - <xs:complexType name="value"> - <xs:attribute name="string-value" type="xs:string"/> - <xs:attribute name="int-value" type="xs:string"/> - </xs:complexType> -</xs:schema> diff --git a/services/core/xsd/cec-config/schema/current.txt b/services/core/xsd/cec-config/schema/current.txt deleted file mode 100644 index 75872d4fb8a7..000000000000 --- a/services/core/xsd/cec-config/schema/current.txt +++ /dev/null @@ -1,44 +0,0 @@ -// Signature format: 2.0 -package com.android.server.hdmi.cec.config { - - public class CecSettings { - ctor public CecSettings(); - method public java.util.List<com.android.server.hdmi.cec.config.Setting> getSetting(); - } - - public class Setting { - ctor public Setting(); - method public com.android.server.hdmi.cec.config.ValueList getAllowedValues(); - method public com.android.server.hdmi.cec.config.Value getDefaultValue(); - method public String getName(); - method public boolean getUserConfigurable(); - method public String getValueType(); - method public void setAllowedValues(com.android.server.hdmi.cec.config.ValueList); - method public void setDefaultValue(com.android.server.hdmi.cec.config.Value); - method public void setName(String); - method public void setUserConfigurable(boolean); - method public void setValueType(String); - } - - public class Value { - ctor public Value(); - method public String getIntValue(); - method public String getStringValue(); - method public void setIntValue(String); - method public void setStringValue(String); - } - - public class ValueList { - ctor public ValueList(); - method public java.util.List<com.android.server.hdmi.cec.config.Value> getValue(); - } - - public class XmlParser { - ctor public XmlParser(); - method public static com.android.server.hdmi.cec.config.CecSettings read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; - method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; - method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; - } - -} - diff --git a/services/core/xsd/cec-config/schema/last_current.txt b/services/core/xsd/cec-config/schema/last_current.txt deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/services/core/xsd/cec-config/schema/last_current.txt +++ /dev/null diff --git a/services/core/xsd/cec-config/schema/last_removed.txt b/services/core/xsd/cec-config/schema/last_removed.txt deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/services/core/xsd/cec-config/schema/last_removed.txt +++ /dev/null diff --git a/services/core/xsd/cec-config/schema/removed.txt b/services/core/xsd/cec-config/schema/removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/services/core/xsd/cec-config/schema/removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index a3dadd835202..2855c70368b1 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -473,7 +473,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // to decide whether an existing policy in the {@link #DEVICE_POLICIES_XML} needs to // be upgraded. See {@link PolicyVersionUpgrader} on instructions how to add an upgrade // step. - static final int DPMS_VERSION = 1; + static final int DPMS_VERSION = 2; static { SECURE_SETTINGS_ALLOWLIST = new ArraySet<>(); @@ -1588,7 +1588,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { CryptoTestHelper.runAndLogSelfTest(); } - public String[] getPersonalAppsForSuspension(int userId) { + public String[] getPersonalAppsForSuspension(@UserIdInt int userId) { return PersonalAppsSuspensionHelper.forUser(mContext, userId) .getPersonalAppsForSuspension(); } @@ -2969,8 +2969,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider { @Override - public boolean isUserDeviceOwner(int userId) { - return mOwners.isDeviceOwnerUserId(userId); + public boolean isDeviceOwner(int userId, ComponentName who) { + return mOwners.isDeviceOwnerUserId(userId) + && mOwners.getDeviceOwnerComponent().equals(who); } @Override @@ -2998,14 +2999,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return component -> findAdmin(component, userId, /* throwForMissingPermission= */ false); } + + @Override + public int[] getUsersForUpgrade() { + List<UserInfo> allUsers = mUserManager.getUsers(); + return allUsers.stream().mapToInt(u -> u.id).toArray(); + } } private void performPolicyVersionUpgrade() { - List<UserInfo> allUsers = mUserManager.getUsers(); PolicyVersionUpgrader upgrader = new PolicyVersionUpgrader( new DpmsUpgradeDataProvider()); - upgrader.upgradePolicy(allUsers.stream().mapToInt(u -> u.id).toArray(), DPMS_VERSION); + upgrader.upgradePolicy(DPMS_VERSION); } private void revertTransferOwnershipIfNecessaryLocked() { @@ -9329,6 +9335,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { dumpResources(pw, mContext, "vendor_cross_profile_apps", R.array.vendor_cross_profile_apps); dumpResources(pw, mContext, "config_packagesExemptFromSuspension", R.array.config_packagesExemptFromSuspension); + dumpResources(pw, mContext, "policy_exempt_apps", R.array.policy_exempt_apps); + dumpResources(pw, mContext, "vendor_policy_exempt_apps", R.array.vendor_policy_exempt_apps); pw.decreaseIndent(); pw.println(); } @@ -10612,6 +10620,30 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public List<String> listPolicyExemptApps() { + Preconditions.checkCallAuthorization( + hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS)); + + // TODO(b/181238156): decide whether it should only list the apps set by the resources, + // or also the "critical" apps defined by PersonalAppsSuspensionHelper (like SMS app). + // If it's the latter, refactor PersonalAppsSuspensionHelper so it (or a superclass) takes + // the resources on constructor. + String[] core = mContext.getResources().getStringArray(R.array.policy_exempt_apps); + String[] vendor = mContext.getResources().getStringArray(R.array.vendor_policy_exempt_apps); + + int size = core.length + vendor.length; + Set<String> apps = new ArraySet<>(size); + for (String app : core) { + apps.add(app); + } + for (String app : vendor) { + apps.add(app); + } + + return new ArrayList<>(apps); + } + + @Override public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner, boolean parent) { Objects.requireNonNull(who, "ComponentName is null"); @@ -14214,10 +14246,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)); enforceCallerSystemUserHandle(); - // no effect if it's called from user build - if (!mInjector.isBuildDebuggable()) { - return; - } final int userId = UserHandle.USER_SYSTEM; boolean isUserCompleted = mInjector.settingsSecureGetIntForUser( Settings.Secure.USER_SETUP_COMPLETE, 0, userId) != 0; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java index 5484a148b0b6..8e31029769d0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java @@ -21,6 +21,7 @@ import android.os.ShellCommand; import com.android.server.devicepolicy.Owners.OwnerDto; import java.io.PrintWriter; +import java.util.Collection; import java.util.List; import java.util.Objects; @@ -30,6 +31,7 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { private static final String CMD_IS_SAFE_OPERATION_BY_REASON = "is-operation-safe-by-reason"; 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 final DevicePolicyManagerService mService; @@ -60,6 +62,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { return runSetSafeOperation(pw); case CMD_LIST_OWNERS: return runListOwners(pw); + case CMD_LIST_POLICY_EXEMPT_APPS: + return runListPolicyExemptApps(pw); default: return onInvalidCommand(pw, cmd); } @@ -88,6 +92,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { + " \n\n"); pw.printf(" %s\n", CMD_LIST_OWNERS); 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"); } private int runIsSafeOperation(PrintWriter pw) { @@ -119,18 +125,20 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { return 0; } - private int runListOwners(PrintWriter pw) { - List<OwnerDto> owners = mService.listAllOwners(); - if (owners.isEmpty()) { - pw.println("none"); + private int printAndGetSize(PrintWriter pw, Collection<?> collection, String nameOnSingular) { + if (collection.isEmpty()) { + pw.printf("no %ss\n", nameOnSingular); return 0; } - int size = owners.size(); - if (size == 1) { - pw.println("1 owner:"); - } else { - pw.printf("%d owners:\n", size); - } + int size = collection.size(); + pw.printf("%d %s%s:\n", size, nameOnSingular, (size == 1 ? "" : "s")); + return size; + } + + private int runListOwners(PrintWriter pw) { + List<OwnerDto> owners = mService.listAllOwners(); + int size = printAndGetSize(pw, owners, "owner"); + if (size == 0) return 0; for (int i = 0; i < size; i++) { OwnerDto owner = owners.get(i); @@ -150,4 +158,17 @@ 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"); + + if (size == 0) return 0; + + for (int i = 0; i < size; i++) { + String app = apps.get(i); + pw.printf(" %d: %s\n", i, app); + } + return 0; + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java index b6420f8ff4bc..19a7659f4d60 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java @@ -33,7 +33,7 @@ public interface PolicyUpgraderDataProvider { * Returns true if the provided {@code userId} is a device owner. May affect some policy * defaults. */ - boolean isUserDeviceOwner(int userId); + boolean isDeviceOwner(int userId, ComponentName who); /** * Returns true if the storage manager indicates file-based encryption is enabled. @@ -60,4 +60,9 @@ public interface PolicyUpgraderDataProvider { * user. */ Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId); + + /** + * Returns the users to upgrade. + */ + int[] getUsersForUpgrade(); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java index cea08634910c..6bc7ba6499ac 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java @@ -62,7 +62,7 @@ public class PolicyVersionUpgrader { * managed profile user IDs. * @param dpmsVersion The version to upgrade to. */ - public void upgradePolicy(int[] allUsers, int dpmsVersion) { + public void upgradePolicy(int dpmsVersion) { int oldVersion = readVersion(); if (oldVersion >= dpmsVersion) { Slog.i(LOG_TAG, String.format("Current version %d, latest version %d, not upgrading.", @@ -70,6 +70,8 @@ public class PolicyVersionUpgrader { return; } + final int[] allUsers = mProvider.getUsersForUpgrade(); + //NOTE: The current version is provided in case the XML file format changes in a // non-backwards-compatible way, so that DeviceAdminData could load it with // old tags, for example. @@ -83,6 +85,27 @@ public class PolicyVersionUpgrader { currentVersion = 1; } + if (currentVersion == 1) { + Slog.i(LOG_TAG, String.format("Upgrading from version %d", currentVersion)); + // This upgrade step is for Device Owner scenario only: For devices upgrading to S, + // if there is a device owner, it retains the ability to control sensors-related + // permission grants. + for (int userId : allUsers) { + DevicePolicyData userData = allUsersData.get(userId); + if (userData == null) { + continue; + } + for (ActiveAdmin admin : userData.mAdminList) { + if (mProvider.isDeviceOwner(userId, admin.info.getComponent())) { + Slog.i(LOG_TAG, String.format( + "Marking Device Owner in user %d for permission grant ", userId)); + admin.mAdminCanGrantSensorsPermissions = true; + } + } + } + currentVersion = 2; + } + writePoliciesAndVersion(allUsers, allUsersData, currentVersion); } diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp index 5ffbd771764d..5140b9f6db58 100644 --- a/services/incremental/Android.bp +++ b/services/incremental/Android.bp @@ -68,6 +68,7 @@ cc_defaults { "libutils", "libvold_binder", "libc++fs", + "libziparchive_for_incfs", ], shared_libs: [ "libandroidfw", @@ -77,7 +78,6 @@ cc_defaults { "libincfs", "liblog", "libz", - "libziparchive", ], } diff --git a/services/tests/servicestests/src/com/android/server/power/FaceDownDetectorTest.java b/services/tests/mockingservicestests/src/com/android/server/power/FaceDownDetectorTest.java index ef20ee7e6ecd..8ecb07158564 100644 --- a/services/tests/servicestests/src/com/android/server/power/FaceDownDetectorTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/power/FaceDownDetectorTest.java @@ -16,59 +16,74 @@ package com.android.server.power; +import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE; + +import static com.android.server.power.FaceDownDetector.KEY_FEATURE_ENABLED; + import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; + import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorManager; +import android.os.PowerManager; +import android.provider.DeviceConfig; import android.testing.TestableContext; import androidx.test.platform.app.InstrumentationRegistry; -import com.android.server.display.TestUtils; +import com.android.server.testables.TestableDeviceConfig; import org.junit.Before; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.time.Duration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class FaceDownDetectorTest { @ClassRule public static final TestableContext sContext = new TestableContext( InstrumentationRegistry.getInstrumentation().getTargetContext(), null); + @Rule + public TestableDeviceConfig.TestableDeviceConfigRule + mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule(); - private final FaceDownDetector mFaceDownDetector = - new FaceDownDetector(this::onFlip); + private final FaceDownDetector mFaceDownDetector = new FaceDownDetector(this::onFlip); @Mock private SensorManager mSensorManager; + @Mock private PowerManager mPowerManager; - private long mCurrentTime; - private int mOnFaceDownCalls = 0; - private int mOnFaceDownExitCalls = 0; + private Duration mCurrentTime; + private int mOnFaceDownCalls; + private int mOnFaceDownExitCalls; @Before - public void setup() { + public void setup() throws Exception { MockitoAnnotations.initMocks(this); sContext.addMockSystemService(SensorManager.class, mSensorManager); - mCurrentTime = 0; + sContext.addMockSystemService(PowerManager.class, mPowerManager); + doReturn(true).when(mPowerManager).isInteractive(); + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_FEATURE_ENABLED, "true", false); + mCurrentTime = Duration.ZERO; + mOnFaceDownCalls = 0; + mOnFaceDownExitCalls = 0; } @Test public void faceDownFor2Seconds_triggersFaceDown() throws Exception { mFaceDownDetector.systemReady(sContext); - // Face up - // Using 0.5 on x to simulate constant acceleration, such as a sloped surface. - mFaceDownDetector.onSensorChanged(createTestEvent(0.5f, 0.0f, 10.0f)); - - for (int i = 0; i < 200; i++) { - advanceTime(Duration.ofMillis(20)); - mFaceDownDetector.onSensorChanged(createTestEvent(0.5f, 0.0f, -10.0f)); - } + triggerFaceDown(); assertThat(mOnFaceDownCalls).isEqualTo(1); assertThat(mOnFaceDownExitCalls).isEqualTo(0); @@ -111,15 +126,7 @@ public class FaceDownDetectorTest { public void faceDownFor2Seconds_followedByFaceUp_triggersFaceDownExit() throws Exception { mFaceDownDetector.systemReady(sContext); - // Face up - // Using 0.5 on x to simulate constant acceleration, such as a sloped surface. - mFaceDownDetector.onSensorChanged(createTestEvent(0.5f, 0.0f, 10.0f)); - - // Trigger face down - for (int i = 0; i < 100; i++) { - advanceTime(Duration.ofMillis(20)); - mFaceDownDetector.onSensorChanged(createTestEvent(0.5f, 0.0f, -10.0f)); - } + triggerFaceDown(); // Phone flips for (int i = 0; i < 10; i++) { @@ -131,8 +138,71 @@ public class FaceDownDetectorTest { assertThat(mOnFaceDownExitCalls).isEqualTo(1); } + @Test + public void notInteractive_doesNotTriggerFaceDown() throws Exception { + doReturn(false).when(mPowerManager).isInteractive(); + mFaceDownDetector.systemReady(sContext); + + triggerFaceDown(); + + assertThat(mOnFaceDownCalls).isEqualTo(0); + assertThat(mOnFaceDownExitCalls).isEqualTo(0); + } + + @Test + public void afterDisablingFeature_doesNotTriggerFaceDown() throws Exception { + mFaceDownDetector.systemReady(sContext); + setEnabled(false); + + triggerFaceDown(); + + assertThat(mOnFaceDownCalls).isEqualTo(0); + } + + @Test + public void afterReenablingWhileNonInteractive_doesNotTriggerFaceDown() throws Exception { + mFaceDownDetector.systemReady(sContext); + setEnabled(false); + + doReturn(false).when(mPowerManager).isInteractive(); + setEnabled(true); + + triggerFaceDown(); + + assertThat(mOnFaceDownCalls).isEqualTo(0); + } + + @Test + public void afterReenablingWhileInteractive_doesTriggerFaceDown() throws Exception { + mFaceDownDetector.systemReady(sContext); + setEnabled(false); + + setEnabled(true); + + triggerFaceDown(); + + assertThat(mOnFaceDownCalls).isEqualTo(1); + } + + private void triggerFaceDown() throws Exception { + // Face up + // Using 0.5 on x to simulate constant acceleration, such as a sloped surface. + mFaceDownDetector.onSensorChanged(createTestEvent(0.5f, 0.0f, 10.0f)); + + for (int i = 0; i < 200; i++) { + advanceTime(Duration.ofMillis(20)); + mFaceDownDetector.onSensorChanged(createTestEvent(0.5f, 0.0f, -10.0f)); + } + } + + private void setEnabled(Boolean enabled) throws Exception { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_FEATURE_ENABLED, enabled.toString(), false); + waitForListenerToHandle(); + } + private void advanceTime(Duration duration) { - mCurrentTime += duration.toNanos(); + mCurrentTime = mCurrentTime.plus(duration); } /** @@ -146,12 +216,11 @@ public class FaceDownDetectorTest { SensorEvent.class.getDeclaredConstructor(int.class); constructor.setAccessible(true); final SensorEvent event = constructor.newInstance(3); - event.sensor = - TestUtils.createSensor(Sensor.TYPE_ACCELEROMETER, Sensor.STRING_TYPE_ACCELEROMETER); + event.sensor = createSensor(Sensor.TYPE_ACCELEROMETER, Sensor.STRING_TYPE_ACCELEROMETER); event.values[0] = x; event.values[1] = y; event.values[2] = gravity; - event.timestamp = mCurrentTime; + event.timestamp = mCurrentTime.toNanos(); return event; } @@ -162,4 +231,25 @@ public class FaceDownDetectorTest { mOnFaceDownExitCalls++; } } + + private Sensor createSensor(int type, String strType) throws Exception { + Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor(); + constr.setAccessible(true); + Sensor sensor = constr.newInstance(); + Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE); + setter.setAccessible(true); + setter.invoke(sensor, type); + if (strType != null) { + Field f = sensor.getClass().getDeclaredField("mStringType"); + f.setAccessible(true); + f.set(sensor, strType); + } + return sensor; + } + + private void waitForListenerToHandle() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + sContext.getMainExecutor().execute(latch::countDown); + assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue(); + } } 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 07f67327b2bf..1c9683803857 100644 --- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java @@ -40,9 +40,11 @@ import android.content.pm.UserInfo; import android.net.Uri; import android.os.RemoteException; import android.os.UserManager; +import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.server.LocalServices; import com.android.server.SystemService; import org.junit.Before; @@ -60,6 +62,7 @@ import java.util.List; * Tests for {@link com.android.server.apphibernation.AppHibernationService} */ @SmallTest +@Presubmit public final class AppHibernationServiceTest { private static final String PACKAGE_SCHEME = "package"; private static final String PACKAGE_NAME_1 = "package1"; @@ -91,6 +94,7 @@ public final class AppHibernationServiceTest { MockitoAnnotations.initMocks(this); doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt()); + LocalServices.removeServiceForTest(AppHibernationManagerInternal.class); mAppHibernationService = new AppHibernationService(new MockInjector(mContext)); verify(mContext).registerReceiver(mReceiverCaptor.capture(), any()); diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/HibernationStateDiskStoreTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/HibernationStateDiskStoreTest.java index 59f3c35f2137..2237c845cde7 100644 --- a/services/tests/servicestests/src/com/android/server/apphibernation/HibernationStateDiskStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/apphibernation/HibernationStateDiskStoreTest.java @@ -19,6 +19,7 @@ package com.android.server.apphibernation; import static org.junit.Assert.assertEquals; import android.os.FileUtils; +import android.platform.test.annotations.Presubmit; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; @@ -48,6 +49,7 @@ import java.util.concurrent.TimeoutException; @SmallTest +@Presubmit public class HibernationStateDiskStoreTest { private static final String STATES_FILE_NAME = "states"; private final MockScheduledExecutorService mMockScheduledExecutorService = diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java index f00edcc85404..fcd6b842426a 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java @@ -120,6 +120,11 @@ class CompatConfigBuilder { return this; } + CompatConfigBuilder addEnabledSinceApexChangeWithId(int sdk, long id) { + mChanges.add(new CompatChange(id, "", -1, sdk, false, false, "", false)); + return this; + } + CompatConfig build() { CompatConfig config = new CompatConfig(mBuildClassifier, mContext); config.forceNonDebuggableFinalForTest(false); diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java index b6b6932c4a93..bd774056aef8 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java @@ -86,6 +86,7 @@ public class CompatConfigTest { // Assume userdebug/eng non-final build when(mBuildClassifier.isDebuggableBuild()).thenReturn(true); when(mBuildClassifier.isFinalBuild()).thenReturn(false); + when(mBuildClassifier.platformTargetSdk()).thenReturn(30); ChangeIdStateCache.disable(); when(mPackageManager.getApplicationInfo(anyString(), anyInt())) .thenThrow(new NameNotFoundException()); @@ -567,6 +568,34 @@ public class CompatConfigTest { } @Test + public void testReadApexConfig() throws IOException { + String configXml = "<config>" + + "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />" + + "<compat-change id=\"1235\" name=\"MY_CHANGE2\" disabled=\"true\" />" + + "<compat-change id=\"1236\" name=\"MY_CHANGE3\" />" + + "<compat-change id=\"1237\" name=\"MY_CHANGE4\" enableSinceTargetSdk=\"31\" />" + + "</config>"; + + File dir = createTempDir(); + writeToFile(dir, "platform_compat_config.xml", configXml); + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + compatConfig.forceNonDebuggableFinalForTest(false); + + compatConfig.initConfigFromLib(dir); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue(); + assertThat(compatConfig.isChangeEnabled(1235L, + ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1236L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue(); + assertThat(compatConfig.isChangeEnabled(1237L, + ApplicationInfoBuilder.create().withTargetSdk(31).build())).isTrue(); + } + + @Test public void testReadConfigMultipleFiles() throws IOException { String configXml1 = "<config>" + "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />" diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java index 0fd6445fbeeb..57fdcd340a02 100644 --- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java @@ -22,6 +22,7 @@ import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARG import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE; import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH; import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE; +import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD; import static com.google.common.truth.Truth.assertThat; @@ -52,6 +53,7 @@ public class OverrideValidatorImplTest { private static final int TARGET_SDK = 10; private static final int TARGET_SDK_BEFORE = 9; private static final int TARGET_SDK_AFTER = 11; + private static final int PLATFORM_SDK_VERSION = 30; @Mock private PackageManager mPackageManager; @@ -61,6 +63,7 @@ public class OverrideValidatorImplTest { private AndroidBuildClassifier debuggableBuild() { AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); when(buildClassifier.isDebuggableBuild()).thenReturn(true); + when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION); return buildClassifier; } @@ -68,6 +71,7 @@ public class OverrideValidatorImplTest { AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); when(buildClassifier.isDebuggableBuild()).thenReturn(false); when(buildClassifier.isFinalBuild()).thenReturn(false); + when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION); return buildClassifier; } @@ -75,6 +79,7 @@ public class OverrideValidatorImplTest { AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); when(buildClassifier.isDebuggableBuild()).thenReturn(false); when(buildClassifier.isFinalBuild()).thenReturn(true); + when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION); return buildClassifier; } @@ -333,6 +338,26 @@ public class OverrideValidatorImplTest { } @Test + public void getOverrideAllowedState_targetSdkChangeGreaterThanOsVersion_rejectOverride() + throws Exception { + final AndroidBuildClassifier buildClassifier = finalBuild(); + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addEnabledSinceApexChangeWithId(PLATFORM_SDK_VERSION + 1, 1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .debuggable() + .build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + assertThat(stateTargetSdkLessChange).isEqualTo( + new OverrideAllowedState(PLATFORM_TOO_OLD, -1, + PLATFORM_SDK_VERSION)); + } + + @Test public void getOverrideAllowedState_finalBuildEnabledChangeDebugApp_rejectOverride() throws Exception { CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java index 799b06734b54..3fc6e9918382 100644 --- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java @@ -78,11 +78,12 @@ public class PlatformCompatTest { when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) .thenThrow(new PackageManager.NameNotFoundException()); mCompatConfig = new CompatConfig(mBuildClassifier, mContext); - mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); + mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier); // Assume userdebug/eng non-final build mCompatConfig.forceNonDebuggableFinalForTest(false); when(mBuildClassifier.isDebuggableBuild()).thenReturn(true); when(mBuildClassifier.isFinalBuild()).thenReturn(false); + when(mBuildClassifier.platformTargetSdk()).thenReturn(30); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); } @@ -99,7 +100,7 @@ public class PlatformCompatTest { .addLoggingOnlyChangeWithId(7L) .addOverridableChangeWithId(8L) .build(); - mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); + mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier); assertThat(mPlatformCompat.listAllChanges()).asList().containsExactly( new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false), new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false), @@ -125,8 +126,9 @@ public class PlatformCompatTest { .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.Q, 5L) .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.R, 6L) .addLoggingOnlyChangeWithId(7L) + .addEnableSinceSdkChangeWithId(31, 8L) .build(); - mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); + mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier); assertThat(mPlatformCompat.listUIChanges()).asList().containsExactly( new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false), new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false), @@ -144,7 +146,7 @@ public class PlatformCompatTest { .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.O, 3L) .build(); mCompatConfig.forceNonDebuggableFinalForTest(true); - mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); + mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier); // Before adding overrides. assertThat(mPlatformCompat.isChangeEnabledByPackageName(1, PACKAGE_NAME, 0)).isTrue(); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 87100a63e35e..77a39d8ac762 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -107,6 +107,7 @@ import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.test.MoreAsserts; // TODO(b/171932723): replace by Truth import android.util.ArraySet; +import android.util.Log; import android.util.Pair; import androidx.test.filters.SmallTest; @@ -154,6 +155,9 @@ import java.util.concurrent.TimeUnit; @SmallTest @Presubmit public class DevicePolicyManagerTest extends DpmTestBase { + + private static final String TAG = DevicePolicyManagerTest.class.getSimpleName(); + private static final List<String> OWNER_SETUP_PERMISSIONS = Arrays.asList( permission.MANAGE_DEVICE_ADMINS, permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL); @@ -3875,32 +3879,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test - public void testForceUpdateUserSetupComplete_userbuild() { - mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - - final int userId = UserHandle.USER_SYSTEM; - // GIVEN userComplete is false in SettingsProvider - setUserSetupCompleteForUser(false, userId); - - // GIVEN userComplete is true in DPM - DevicePolicyData userData = new DevicePolicyData(userId); - userData.mUserSetupComplete = true; - dpms.mUserData.put(UserHandle.USER_SYSTEM, userData); - - // GIVEN it's user build - getServices().buildMock.isDebuggable = false; - - assertThat(dpms.hasUserSetupCompleted()).isTrue(); - - dpm.forceUpdateUserSetupComplete(); - - // THEN the state in dpms is not changed - assertThat(dpms.hasUserSetupCompleted()).isTrue(); - } - - @Test - public void testForceUpdateUserSetupComplete_userDebugbuild() { + public void testForceUpdateUserSetupComplete_forcesUpdate() { mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -3913,9 +3892,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { userData.mUserSetupComplete = true; dpms.mUserData.put(UserHandle.USER_SYSTEM, userData); - // GIVEN it's userdebug build - getServices().buildMock.isDebuggable = true; - assertThat(dpms.hasUserSetupCompleted()).isTrue(); dpm.forceUpdateUserSetupComplete(); @@ -7215,6 +7191,47 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThat(dpm.isUsbDataSignalingEnabled()).isEqualTo(enabled); } + @Test + public void testGetPolicyExemptApps_noPermission() { + assertThrows(SecurityException.class, () -> dpm.getPolicyExemptApps()); + } + + @Test + public void testGetPolicyExemptApps_empty() { + grantManageDeviceAdmins(); + mockPolicyExemptApps(); + mockVendorPolicyExemptApps(); + + assertThat(dpm.getPolicyExemptApps()).isEmpty(); + } + + @Test + public void testGetPolicyExemptApps_baseOnly() { + grantManageDeviceAdmins(); + mockPolicyExemptApps("foo"); + mockVendorPolicyExemptApps(); + + assertThat(dpm.getPolicyExemptApps()).containsExactly("foo"); + } + + @Test + public void testGetPolicyExemptApps_vendorOnly() { + grantManageDeviceAdmins(); + mockPolicyExemptApps(); + mockVendorPolicyExemptApps("bar"); + + assertThat(dpm.getPolicyExemptApps()).containsExactly("bar"); + } + + @Test + public void testGetPolicyExemptApps_baseAndVendor() { + grantManageDeviceAdmins(); + mockPolicyExemptApps("4", "23", "15", "42", "8"); + mockVendorPolicyExemptApps("16", "15", "4"); + + assertThat(dpm.getPolicyExemptApps()).containsExactly("4", "8", "15", "16", "23", "42"); + } + private void setUserUnlocked(int userHandle, boolean unlocked) { when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked); } @@ -7436,4 +7453,18 @@ public class DevicePolicyManagerTest extends DpmTestBase { return new StringParceledListSlice(Arrays.asList(s)); } + private void grantManageDeviceAdmins() { + Log.d(TAG, "Granting " + permission.MANAGE_DEVICE_ADMINS); + mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); + } + + private void mockPolicyExemptApps(String... apps) { + Log.d(TAG, "Mocking R.array.policy_exempt_apps to return " + Arrays.toString(apps)); + when(mContext.resources.getStringArray(R.array.policy_exempt_apps)).thenReturn(apps); + } + + private void mockVendorPolicyExemptApps(String... apps) { + Log.d(TAG, "Mocking R.array.vendor_policy_exempt_apps to return " + Arrays.toString(apps)); + when(mContext.resources.getStringArray(R.array.vendor_policy_exempt_apps)).thenReturn(apps); + } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java index f94b800afbef..2fe2f40f34be 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java @@ -21,6 +21,11 @@ import static com.google.common.truth.Truth.assertThat; import android.app.admin.DeviceAdminInfo; import android.content.ComponentName; import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.os.Parcel; +import android.util.TypedXmlPullParser; +import android.util.Xml; import androidx.test.InstrumentationRegistry; @@ -32,9 +37,14 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; @@ -44,18 +54,22 @@ import java.util.function.Function; public class PolicyVersionUpgraderTest { // NOTE: Only change this value if the corresponding CL also adds a test to test the upgrade // to the new version. - private static final int LATEST_TESTED_VERSION = 1; + private static final int LATEST_TESTED_VERSION = 2; + public static final String PERMISSIONS_TAG = "admin-can-grant-sensors-permissions"; + private ComponentName mFakeAdmin; private static class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider { int mDeviceOwnerUserId; + ComponentName mDeviceOwnerComponent = new ComponentName("", ""); boolean mIsFileBasedEncryptionEnabled; Map<Integer, ComponentName> mUserToComponent = new HashMap<>(); - Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo; + Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo = new HashMap<>(); File mDataDir; + int[] mUsers; @Override - public boolean isUserDeviceOwner(int userId) { - return userId == mDeviceOwnerUserId; + public boolean isDeviceOwner(int userId, ComponentName who) { + return userId == mDeviceOwnerUserId && mDeviceOwnerComponent.equals(who); } @Override @@ -92,6 +106,11 @@ public class PolicyVersionUpgraderTest { public Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId) { return componentName -> mComponentToDeviceAdminInfo.get(componentName); } + + @Override + public int[] getUsersForUpgrade() { + return mUsers; + } } private final Context mRealTestContext = InstrumentationRegistry.getTargetContext(); @@ -105,38 +124,69 @@ public class PolicyVersionUpgraderTest { mUpgrader = new PolicyVersionUpgrader(mProvider); mDataDir = new File(mRealTestContext.getCacheDir(), "test-data"); mDataDir.getParentFile().mkdirs(); + // Prepare provider. mProvider.mDataDir = mDataDir; + mFakeAdmin = new ComponentName( + "com.android.frameworks.servicestests", + "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"); + ActivityInfo activityInfo = createActivityInfo(mFakeAdmin); + DeviceAdminInfo dai = createDeviceAdminInfo(activityInfo); + mProvider.mComponentToDeviceAdminInfo.put(mFakeAdmin, dai); + mProvider.mUsers = new int[] {0}; } @Test public void testSameVersionDoesNothing() throws IOException { - int[] users = new int[] {0}; writeVersionToXml(DevicePolicyManagerService.DPMS_VERSION); - preparePoliciesFile(users[0]); - String oldContents = readPoliciesFile(0); + final int userId = mProvider.mUsers[0]; + preparePoliciesFile(userId); + String oldContents = readPoliciesFile(userId); - mUpgrader.upgradePolicy(users, DevicePolicyManagerService.DPMS_VERSION); + mUpgrader.upgradePolicy(DevicePolicyManagerService.DPMS_VERSION); String newContents = readPoliciesFile(0); assertThat(newContents).isEqualTo(oldContents); } @Test - public void testUpgrade0To1RemovesPasswordMetrics() throws IOException { - int[] users = new int[] {0, 10}; + public void testUpgrade0To1RemovesPasswordMetrics() throws IOException, XmlPullParserException { + final String activePasswordTag = "active-password"; + mProvider.mUsers = new int[] {0, 10}; writeVersionToXml(0); - for (int userId : users) { + for (int userId : mProvider.mUsers) { preparePoliciesFile(userId); } + // Validate test set-up. + assertThat(isTagPresent(readPoliciesFileToStream(0), activePasswordTag)).isTrue(); + + mUpgrader.upgradePolicy(1); + + assertThat(readVersionFromXml()).isGreaterThan(1); + for (int user: mProvider.mUsers) { + assertThat(isTagPresent(readPoliciesFileToStream(user), activePasswordTag)).isFalse(); + } + } - String oldContents = readPoliciesFile(0); - assertThat(oldContents).contains("active-password"); + @Test + public void testUpgrade1To2MarksDoForPermissionControl() + throws IOException, XmlPullParserException { + final int ownerUser = 10; + mProvider.mUsers = new int[] {0, ownerUser}; + writeVersionToXml(1); + for (int userId : mProvider.mUsers) { + preparePoliciesFile(userId); + } + mProvider.mDeviceOwnerUserId = ownerUser; + mProvider.mDeviceOwnerComponent = mFakeAdmin; + mProvider.mUserToComponent.put(ownerUser, mFakeAdmin); - mUpgrader.upgradePolicy(users, 1); + mUpgrader.upgradePolicy(2); - assertThat(readVersionFromXml()).isEqualTo(1); - assertThat(readPoliciesFile(users[0])).doesNotContain("active-password"); - assertThat(readPoliciesFile(users[1])).doesNotContain("active-password"); + assertThat(readVersionFromXml()).isEqualTo(2); + assertThat(getBooleanValueTag(readPoliciesFileToStream(mProvider.mUsers[0]), + PERMISSIONS_TAG)).isFalse(); + assertThat(getBooleanValueTag(readPoliciesFileToStream(ownerUser), + PERMISSIONS_TAG)).isTrue(); } @Test @@ -169,6 +219,70 @@ public class PolicyVersionUpgraderTest { private String readPoliciesFile(int userId) throws IOException { File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead(); - return new String(Files.asByteSource(policiesFile).read()); + FileReader reader = new FileReader(policiesFile); + return new String(Files.asByteSource(policiesFile).read(), Charset.defaultCharset()); + } + + private InputStream readPoliciesFileToStream(int userId) throws IOException { + File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead(); + return new FileInputStream(policiesFile); + } + + private boolean getBooleanValueTag(InputStream inputXml, String tagName) + throws IOException, XmlPullParserException { + TypedXmlPullParser parser = Xml.resolvePullParser(inputXml); + + int eventType = parser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + String tag = parser.getName(); + if (tagName.equals(tag)) { + String res = parser.getAttributeValue(null, "value"); + return Boolean.parseBoolean(res); + } + } + eventType = parser.next(); + } + + throw new IllegalStateException("Could not find " + tagName); + } + + private boolean isTagPresent(InputStream inputXml, String tagName) + throws IOException, XmlPullParserException { + TypedXmlPullParser parser = Xml.resolvePullParser(inputXml); + + int eventType = parser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + String tag = parser.getName(); + if (tagName.equals(tag)) { + return true; + } + } + eventType = parser.next(); + } + + return false; + } + + private ActivityInfo createActivityInfo(ComponentName admin) { + ActivityInfo ai = new ActivityInfo(); + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.className = admin.getClassName(); + applicationInfo.uid = 2222; + ai.applicationInfo = applicationInfo; + ai.name = admin.getClassName(); + ai.packageName = admin.getPackageName(); + return ai; + } + + private DeviceAdminInfo createDeviceAdminInfo(ActivityInfo activityInfo) { + Parcel parcel = Parcel.obtain(); + activityInfo.writeToParcel(parcel, 0); + parcel.writeInt(0); + parcel.writeBoolean(true); + parcel.setDataPosition(0); + + return DeviceAdminInfo.CREATOR.createFromParcel(parcel); } } 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 843296e31800..dbb415c88a5f 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 @@ -68,7 +68,7 @@ public final class UpdatableFontDirTest { */ private static class FakeFontFileParser implements UpdatableFontDir.FontFileParser { @Override - public String getPostScriptName(File file) throws IOException { + public String getCanonicalFileName(File file) throws IOException { String content = FileUtils.readTextFile(file, 100, ""); return content.split(",")[0]; } @@ -160,10 +160,10 @@ public final class UpdatableFontDirTest { assertThat(dirForPreparation.getSystemFontConfig().getLastModifiedTimeMillis()) .isEqualTo(expectedModifiedDate); dirForPreparation.update(Arrays.asList( - newFontUpdateRequest("foo,1", GOOD_SIGNATURE), - newFontUpdateRequest("bar,2", GOOD_SIGNATURE), - newFontUpdateRequest("foo,3", GOOD_SIGNATURE), - newFontUpdateRequest("bar,4", GOOD_SIGNATURE), + newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE), + newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE), + newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE), + newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE), newAddFontFamilyRequest("<family name='foobar'>" + " <font>foo.ttf</font>" + " <font>bar.ttf</font>" @@ -214,10 +214,10 @@ public final class UpdatableFontDirTest { mConfigFile); dirForPreparation.loadFontFileMap(); dirForPreparation.update(Arrays.asList( - newFontUpdateRequest("foo,1", GOOD_SIGNATURE), - newFontUpdateRequest("bar,2", GOOD_SIGNATURE), - newFontUpdateRequest("foo,3", GOOD_SIGNATURE), - newFontUpdateRequest("bar,4", GOOD_SIGNATURE), + newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE), + newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE), + newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE), + newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE), newAddFontFamilyRequest("<family name='foobar'>" + " <font>foo.ttf</font>" + " <font>bar.ttf</font>" @@ -246,10 +246,10 @@ public final class UpdatableFontDirTest { mConfigFile); dirForPreparation.loadFontFileMap(); dirForPreparation.update(Arrays.asList( - newFontUpdateRequest("foo,1", GOOD_SIGNATURE), - newFontUpdateRequest("bar,2", GOOD_SIGNATURE), - newFontUpdateRequest("foo,3", GOOD_SIGNATURE), - newFontUpdateRequest("bar,4", GOOD_SIGNATURE), + newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE), + newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE), + newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE), + newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE), newAddFontFamilyRequest("<family name='foobar'>" + " <font>foo.ttf</font>" + " <font>bar.ttf</font>" @@ -279,10 +279,10 @@ public final class UpdatableFontDirTest { mConfigFile); dirForPreparation.loadFontFileMap(); dirForPreparation.update(Arrays.asList( - newFontUpdateRequest("foo,1", GOOD_SIGNATURE), - newFontUpdateRequest("bar,2", GOOD_SIGNATURE), - newFontUpdateRequest("foo,3", GOOD_SIGNATURE), - newFontUpdateRequest("bar,4", GOOD_SIGNATURE), + newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE), + newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE), + newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE), + newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE), newAddFontFamilyRequest("<family name='foobar'>" + " <font>foo.ttf</font>" + " <font>bar.ttf</font>" @@ -332,14 +332,14 @@ public final class UpdatableFontDirTest { mConfigFile); dirForPreparation.loadFontFileMap(); dirForPreparation.update(Arrays.asList( - newFontUpdateRequest("foo,1", GOOD_SIGNATURE), + newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE), newAddFontFamilyRequest("<family name='foobar'>" + " <font>foo.ttf</font>" + "</family>"))); try { dirForPreparation.update(Arrays.asList( - newFontUpdateRequest("foo,2", GOOD_SIGNATURE), - newFontUpdateRequest("bar,2", "Invalid signature"), + newFontUpdateRequest("foo.ttf,2", GOOD_SIGNATURE), + newFontUpdateRequest("bar.ttf,2", "Invalid signature"), newAddFontFamilyRequest("<family name='foobar'>" + " <font>foo.ttf</font>" + " <font>bar.ttf</font>" @@ -372,7 +372,7 @@ public final class UpdatableFontDirTest { mConfigFile); dir.loadFontFileMap(); - dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE))); assertThat(dir.getFontFileMap()).containsKey("test.ttf"); assertThat(parser.getRevision(dir.getFontFileMap().get("test.ttf"))).isEqualTo(1); File fontFile = dir.getFontFileMap().get("test.ttf"); @@ -390,9 +390,9 @@ public final class UpdatableFontDirTest { mConfigFile); dir.loadFontFileMap(); - dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE))); Map<String, File> mapBeforeUpgrade = dir.getFontFileMap(); - dir.update(Collections.singletonList(newFontUpdateRequest("test,2", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,2", GOOD_SIGNATURE))); assertThat(dir.getFontFileMap()).containsKey("test.ttf"); assertThat(parser.getRevision(dir.getFontFileMap().get("test.ttf"))).isEqualTo(2); assertThat(mapBeforeUpgrade).containsKey("test.ttf"); @@ -409,9 +409,10 @@ public final class UpdatableFontDirTest { mConfigFile); dir.loadFontFileMap(); - dir.update(Collections.singletonList(newFontUpdateRequest("test,2", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,2", GOOD_SIGNATURE))); try { - dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1", + GOOD_SIGNATURE))); fail("Expect SystemFontException"); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()).isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING); @@ -430,8 +431,8 @@ public final class UpdatableFontDirTest { mConfigFile); dir.loadFontFileMap(); - dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE))); - dir.update(Collections.singletonList(newFontUpdateRequest("bar,2", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE))); assertThat(dir.getFontFileMap()).containsKey("foo.ttf"); assertThat(parser.getRevision(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(1); assertThat(dir.getFontFileMap()).containsKey("bar.ttf"); @@ -448,8 +449,8 @@ public final class UpdatableFontDirTest { dir.loadFontFileMap(); dir.update(Arrays.asList( - newFontUpdateRequest("foo,1", GOOD_SIGNATURE), - newFontUpdateRequest("bar,2", GOOD_SIGNATURE))); + newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE), + newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE))); assertThat(dir.getFontFileMap()).containsKey("foo.ttf"); assertThat(parser.getRevision(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(1); assertThat(dir.getFontFileMap()).containsKey("bar.ttf"); @@ -467,7 +468,8 @@ public final class UpdatableFontDirTest { try { dir.update( - Collections.singletonList(newFontUpdateRequest("test,1", "Invalid signature"))); + Collections.singletonList(newFontUpdateRequest("test.ttf,1", + "Invalid signature"))); fail("Expect SystemFontException"); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()) @@ -480,14 +482,15 @@ public final class UpdatableFontDirTest { public void installFontFile_olderThanPreinstalledFont() throws Exception { FakeFontFileParser parser = new FakeFontFileParser(); FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); - FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test,1"); + FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test.ttf,1"); UpdatableFontDir dir = new UpdatableFontDir( mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil, mConfigFile); dir.loadFontFileMap(); try { - dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1", + GOOD_SIGNATURE))); fail("Expect SystemFontException"); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()).isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING); @@ -500,7 +503,7 @@ public final class UpdatableFontDirTest { long expectedModifiedDate = 1234567890; FakeFontFileParser parser = new FakeFontFileParser(); FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); - FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test,1"); + FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test.ttf,1"); File readonlyDir = new File(mCacheDir, "readonly"); assertThat(readonlyDir.mkdir()).isTrue(); @@ -519,7 +522,8 @@ public final class UpdatableFontDirTest { try { dir.update( - Collections.singletonList(newFontUpdateRequest("test,2", GOOD_SIGNATURE))); + Collections.singletonList(newFontUpdateRequest("test.ttf,2", + GOOD_SIGNATURE))); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()) .isEqualTo(FontManager.RESULT_ERROR_FAILED_UPDATE_CONFIG); @@ -539,7 +543,7 @@ public final class UpdatableFontDirTest { mUpdatableFontFilesDir, mPreinstalledFontDirs, new UpdatableFontDir.FontFileParser() { @Override - public String getPostScriptName(File file) throws IOException { + public String getCanonicalFileName(File file) throws IOException { return null; } @@ -551,7 +555,8 @@ public final class UpdatableFontDirTest { dir.loadFontFileMap(); try { - dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1", + GOOD_SIGNATURE))); fail("Expect SystemFontException"); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()) @@ -567,7 +572,7 @@ public final class UpdatableFontDirTest { mUpdatableFontFilesDir, mPreinstalledFontDirs, new UpdatableFontDir.FontFileParser() { @Override - public String getPostScriptName(File file) throws IOException { + public String getCanonicalFileName(File file) throws IOException { throw new IOException(); } @@ -579,7 +584,8 @@ public final class UpdatableFontDirTest { dir.loadFontFileMap(); try { - dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1", + GOOD_SIGNATURE))); fail("Expect SystemFontException"); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()) @@ -615,7 +621,8 @@ public final class UpdatableFontDirTest { dir.loadFontFileMap(); try { - dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1", + GOOD_SIGNATURE))); fail("Expect SystemFontException"); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()) @@ -633,11 +640,11 @@ public final class UpdatableFontDirTest { mConfigFile); dir.loadFontFileMap(); - dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE))); + dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE))); try { dir.update(Arrays.asList( - newFontUpdateRequest("foo,2", GOOD_SIGNATURE), - newFontUpdateRequest("bar,2", "Invalid signature"))); + newFontUpdateRequest("foo.ttf,2", GOOD_SIGNATURE), + newFontUpdateRequest("bar.ttf,2", "Invalid signature"))); fail("Batch update with invalid signature should fail"); } catch (FontManagerService.SystemFontException e) { // Expected @@ -657,7 +664,7 @@ public final class UpdatableFontDirTest { dir.loadFontFileMap(); dir.update(Arrays.asList( - newFontUpdateRequest("test,1", GOOD_SIGNATURE), + newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE), newAddFontFamilyRequest("<family name='test'>" + " <font>test.ttf</font>" + "</family>"))); @@ -680,7 +687,7 @@ public final class UpdatableFontDirTest { try { dir.update(Arrays.asList( - newFontUpdateRequest("test,1", GOOD_SIGNATURE), + newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE), newAddFontFamilyRequest("<family lang='en'>" + " <font>test.ttf</font>" + "</family>"))); @@ -722,7 +729,7 @@ public final class UpdatableFontDirTest { assertNamedFamilyExists(dir.getSystemFontConfig(), "monospace"); dir.update(Arrays.asList( - newFontUpdateRequest("test,1", GOOD_SIGNATURE), + newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE), // Updating an existing font family. newAddFontFamilyRequest("<family name='monospace'>" + " <font>test.ttf</font>" @@ -755,7 +762,7 @@ public final class UpdatableFontDirTest { assertThat(firstFontFamily.getName()).isNotEmpty(); dir.update(Arrays.asList( - newFontUpdateRequest("test,1", GOOD_SIGNATURE), + newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE), newAddFontFamilyRequest("<family name='" + firstFontFamily.getName() + "'>" + " <font>test.ttf</font>" + "</family>"))); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java index 137bd88b1489..375704ee31bf 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java @@ -16,183 +16,206 @@ package com.android.server.hdmi; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + import android.annotation.NonNull; import android.content.Context; -import android.util.Slog; - -import com.android.server.hdmi.cec.config.CecSettings; -import com.android.server.hdmi.cec.config.XmlParser; - -import org.xmlpull.v1.XmlPullParserException; +import android.content.ContextWrapper; +import android.content.res.Resources; -import java.io.ByteArrayInputStream; -import java.io.IOException; - -import javax.xml.datatype.DatatypeConfigurationException; +import com.android.internal.R; /** - * Fake class which loads default system configuration with user-configurable + * Fake class which stubs default system configuration with user-configurable * settings (useful for testing). */ final class FakeHdmiCecConfig extends HdmiCecConfig { private static final String TAG = "FakeHdmiCecConfig"; - private static final String SYSTEM_CONFIG_XML = - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + " <setting name=\"power_state_change_on_active_source_lost\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"none\" />" - + " <value string-value=\"standby_now\" />" - + " </allowed-values>" - + " <default-value string-value=\"none\" />" - + " </setting>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + " <setting name=\"hdmi_cec_version\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0x05\" />" - + " <value int-value=\"0x06\" />" - + " </allowed-values>" - + " <default-value int-value=\"0x05\" />" - + " </setting>" - + " <setting name=\"system_audio_mode_muting\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + " <setting name=\"volume_control_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + " <setting name=\"tv_wake_on_one_touch_play\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + " <setting name=\"tv_send_standby_on_sleep\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + " <setting name=\"rc_profile_tv\"" - + " value-type=\"int\"" - + " user-configurable=\"false\">" - + " <allowed-values>" - + " <value int-value=\"0x0\" />" - + " <value int-value=\"0x2\" />" - + " <value int-value=\"0x6\" />" - + " <value int-value=\"0xA\" />" - + " <value int-value=\"0xE\" />" - + " </allowed-values>" - + " <default-value int-value=\"0x0\" />" - + " </setting>" - + " <setting name=\"rc_profile_source_handles_root_menu\"" - + " value-type=\"int\"" - + " user-configurable=\"false\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + " <setting name=\"rc_profile_source_handles_setup_menu\"" - + " value-type=\"int\"" - + " user-configurable=\"false\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + " <setting name=\"rc_profile_source_handles_contents_menu\"" - + " value-type=\"int\"" - + " user-configurable=\"false\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"0\" />" - + " </setting>" - + " <setting name=\"rc_profile_source_handles_top_menu\"" - + " value-type=\"int\"" - + " user-configurable=\"false\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"0\" />" - + " </setting>" - + " <setting name=\"rc_profile_source_handles_media_context_sensitive_menu\"" - + " value-type=\"int\"" - + " user-configurable=\"false\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"0\" />" - + " </setting>" - + "</cec-settings>"; + public static Context buildContext(Context context) { + Context contextSpy = spy(new ContextWrapper(context)); + doReturn(buildResources(context)).when(contextSpy).getResources(); + return contextSpy; + } - FakeHdmiCecConfig(@NonNull Context context) { - super(context, new StorageAdapter(context), parseFromString(SYSTEM_CONFIG_XML), null); + private static Resources buildResources(Context context) { + Resources resources = spy(context.getResources()); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecHdmiCecEnabled_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecHdmiCecControlEnabled_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecHdmiCecControlEnabled_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecHdmiCecControlDisabled_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecHdmiCecControlDisabled_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecHdmiCecVersion_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecHdmiCecVersion14b_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecHdmiCecVersion14b_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecHdmiCecVersion20_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecHdmiCecVersion20_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecSendStandbyOnSleep_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecPowerControlModeTv_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecPowerControlModeTv_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecPowerControlModeBroadcast_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecPowerControlModeBroadcast_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecPowerControlModeNone_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecPowerControlModeNone_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecPowerStateChangeOnActiveSourceLost_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecSystemAudioModeMuting_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecSystemAudioModeMutingEnabled_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecSystemAudioModeMutingEnabled_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecSystemAudioModeMutingDisabled_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecSystemAudioModeMutingDisabled_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecVolumeControlMode_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecVolumeControlModeEnabled_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecVolumeControlModeEnabled_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecVolumeControlModeDisabled_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecVolumeControlModeDisabled_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecTvWakeOnOneTouchPlay_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecTvWakeOnOneTouchPlayEnabled_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecTvWakeOnOneTouchPlayEnabled_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecTvWakeOnOneTouchPlayDisabled_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecTvWakeOnOneTouchPlayDisabled_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecTvSendStandbyOnSleep_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecTvSendStandbyOnSleepEnabled_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecTvSendStandbyOnSleepEnabled_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecTvSendStandbyOnSleepDisabled_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecTvSendStandbyOnSleepDisabled_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileTv_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileTvNone_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileTvNone_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileTvOne_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecRcProfileTvOne_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileTvTwo_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecRcProfileTvTwo_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileTvThree_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecRcProfileTvThree_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileTvFour_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecRcProfileTvFour_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceRootMenu_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceRootMenuHandled_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceRootMenuHandled_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceRootMenuNotHandled_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceRootMenuNotHandled_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceSetupMenu_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceSetupMenuHandled_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceSetupMenuHandled_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceSetupMenuNotHandled_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceSetupMenuNotHandled_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceContentsMenu_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceContentsMenuHandled_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceContentsMenuHandled_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceContentsMenuNotHandled_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceContentsMenuNotHandled_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceTopMenu_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceTopMenuHandled_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceTopMenuHandled_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceTopMenuNotHandled_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceTopMenuNotHandled_default); + + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed); + doReturn(false).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed); + doReturn(true).when(resources).getBoolean( + R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default); + + return resources; } - private static CecSettings parseFromString(@NonNull String configXml) { - CecSettings config = null; - try { - config = XmlParser.read( - new ByteArrayInputStream(configXml.getBytes())); - } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) { - Slog.e(TAG, "Encountered an error while reading/parsing CEC config strings", e); - } - return config; + FakeHdmiCecConfig(@NonNull Context context) { + super(buildContext(context), new StorageAdapter(context)); } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java index 798cf85957c0..c834510ba24c 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -27,6 +28,7 @@ import static org.testng.Assert.assertThrows; import android.annotation.NonNull; import android.content.Context; +import android.content.res.Resources; import android.hardware.hdmi.HdmiControlManager; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; @@ -35,6 +37,8 @@ import android.provider.Settings.Global; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; +import com.android.internal.R; + import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -61,265 +65,118 @@ public final class HdmiCecConfigTest { @Mock private HdmiCecConfig.StorageAdapter mStorageAdapter; @Mock private HdmiCecConfig.SettingChangeListener mSettingChangeListener; + private void setBooleanResource(int resId, boolean value) { + Resources resources = mContext.getResources(); + doReturn(value).when(resources).getBoolean(resId); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mContext = InstrumentationRegistry.getTargetContext(); - } - - @Test - public void getAllCecSettings_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThat(hdmiCecConfig.getAllSettings()).isEmpty(); - } - - @Test - public void getAllCecSettings_Empty() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); - assertThat(hdmiCecConfig.getAllSettings()).isEmpty(); + mContext = FakeHdmiCecConfig.buildContext(InstrumentationRegistry.getTargetContext()); } @Test public void getAllCecSettings_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"false\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getAllSettings()) .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, - HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE); - } - - @Test - public void getUserCecSettings_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThat(hdmiCecConfig.getUserSettings()).isEmpty(); - } - - @Test - public void getUserCecSettings_Empty() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); - assertThat(hdmiCecConfig.getUserSettings()).isEmpty(); - } - - @Test - public void getUserCecSettings_OnlyMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, + HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE, + HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, + HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY, + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU, + HdmiControlManager + .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU); + } + + @Test + public void getUserCecSettings_BasicSanity() { + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getUserSettings()) .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, - HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE); + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, + HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE, + HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, + HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY, + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU, + HdmiControlManager + .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU); } @Test public void getUserCecSettings_WithOverride() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"false\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>"); + setBooleanResource(R.bool.config_cecHdmiCecEnabled_userConfigurable, false); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getUserSettings()) - .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED); - } - - @Test - public void isStringValueType_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThrows(IllegalArgumentException.class, - () -> hdmiCecConfig.isStringValueType("foo")); + .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, + HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE, + HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, + HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY, + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU, + HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU, + HdmiControlManager + .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU); } @Test public void isStringValueType_InvalidSetting() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.isStringValueType("foo")); } @Test public void isStringValueType_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertTrue(hdmiCecConfig.isStringValueType( HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE)); } @Test - public void isIntValueType_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThrows(IllegalArgumentException.class, - () -> hdmiCecConfig.isIntValueType("foo")); - } - - @Test public void isIntValueType_InvalidSetting() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.isIntValueType("foo")); } @Test public void isIntValueType_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertTrue(hdmiCecConfig.isIntValueType( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)); } @Test - public void getAllowedStringValues_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThrows(IllegalArgumentException.class, - () -> hdmiCecConfig.getAllowedStringValues("foo")); - } - - @Test public void getAllowedStringValues_InvalidSetting() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getAllowedStringValues("foo")); } @Test public void getAllowedStringValues_InvalidValueType() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getAllowedStringValues( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)); @@ -327,21 +184,7 @@ public final class HdmiCecConfigTest { @Test public void getAllowedStringValues_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getAllowedStringValues( HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE)) .containsExactly(HdmiControlManager.POWER_CONTROL_MODE_TV, @@ -350,41 +193,25 @@ public final class HdmiCecConfigTest { } @Test - public void getAllowedIntValues_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThrows(IllegalArgumentException.class, - () -> hdmiCecConfig.getAllowedIntValues("foo")); + public void getAllowedStringValues_WithOverride() { + setBooleanResource(R.bool.config_cecPowerControlModeNone_allowed, false); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); + assertThat(hdmiCecConfig.getAllowedStringValues( + HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE)) + .containsExactly(HdmiControlManager.POWER_CONTROL_MODE_TV, + HdmiControlManager.POWER_CONTROL_MODE_BROADCAST); } @Test public void getAllowedIntValues_InvalidSetting() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getAllowedIntValues("foo")); } @Test public void getAllowedIntValues_InvalidValueType() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getAllowedIntValues( HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE)); @@ -392,20 +219,7 @@ public final class HdmiCecConfigTest { @Test public void getAllowedIntValues_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getAllowedIntValues( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)) .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED, @@ -413,62 +227,24 @@ public final class HdmiCecConfigTest { } @Test - public void getAllowedIntValues_HexValues() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0x00\" />" - + " <value int-value=\"0x01\" />" - + " </allowed-values>" - + " <default-value int-value=\"0x01\" />" - + " </setting>" - + "</cec-settings>", null); + public void getAllowedIntValues_WithOverride() { + setBooleanResource(R.bool.config_cecHdmiCecControlDisabled_allowed, false); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getAllowedIntValues( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)) - .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED, - HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); - } - - @Test - public void getDefaultStringValue_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThrows(IllegalArgumentException.class, - () -> hdmiCecConfig.getDefaultStringValue("foo")); + .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); } @Test public void getDefaultStringValue_InvalidSetting() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getDefaultStringValue("foo")); } @Test public void getDefaultStringValue_InvalidValueType() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getDefaultStringValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)); @@ -476,62 +252,46 @@ public final class HdmiCecConfigTest { @Test public void getDefaultStringValue_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getDefaultStringValue( HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE)) .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_TV); } @Test - public void getDefaultIntValue_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThrows(IllegalArgumentException.class, - () -> hdmiCecConfig.getDefaultIntValue("foo")); + public void getDefaultStringValue_WithOverride() { + setBooleanResource(R.bool.config_cecPowerControlModeTv_default, false); + setBooleanResource(R.bool.config_cecPowerControlModeBroadcast_default, true); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); + assertThat(hdmiCecConfig.getDefaultStringValue( + HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE)) + .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST); + } + + @Test + public void getDefaultStringValue_MultipleDefaults() { + setBooleanResource(R.bool.config_cecPowerControlModeBroadcast_default, true); + assertThrows(RuntimeException.class, + () -> new HdmiCecConfig(mContext, mStorageAdapter)); + } + + @Test + public void getDefaultStringValue_NoDefault() { + setBooleanResource(R.bool.config_cecPowerControlModeTv_default, false); + assertThrows(RuntimeException.class, + () -> new HdmiCecConfig(mContext, mStorageAdapter)); } @Test public void getDefaultIntValue_InvalidSetting() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getDefaultIntValue("foo")); } @Test public void getDefaultIntValue_InvalidValueType() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getDefaultIntValue( HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE)); @@ -539,81 +299,32 @@ public final class HdmiCecConfigTest { @Test public void getDefaultIntValue_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getDefaultIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)) .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); } @Test - public void getDefaultIntValue_HexValue() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0x00\" />" - + " <value int-value=\"0x01\" />" - + " </allowed-values>" - + " <default-value int-value=\"0x01\" />" - + " </setting>" - + "</cec-settings>", null); + public void getDefaultIntValue_WithOverride() { + setBooleanResource(R.bool.config_cecHdmiCecControlEnabled_default, false); + setBooleanResource(R.bool.config_cecHdmiCecControlDisabled_default, true); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getDefaultIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)) - .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); - } - - @Test - public void getStringValue_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThrows(IllegalArgumentException.class, - () -> hdmiCecConfig.getStringValue("foo")); + .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); } @Test public void getStringValue_InvalidSetting() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getStringValue("foo")); } @Test public void getStringValue_InvalidType() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getStringValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)); @@ -625,21 +336,7 @@ public final class HdmiCecConfigTest { Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP, HdmiControlManager.POWER_CONTROL_MODE_TV)) .thenReturn(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST); - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getStringValue( HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE)) .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST); @@ -652,61 +349,22 @@ public final class HdmiCecConfigTest { HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE)) .thenReturn( HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW); - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"power_state_change_on_active_source_lost\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"none\" />" - + " <value string-value=\"standby_now\" />" - + " </allowed-values>" - + " <default-value string-value=\"none\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getStringValue( HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST)) .isEqualTo(HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW); } @Test - public void getIntValue_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThrows(IllegalArgumentException.class, - () -> hdmiCecConfig.getIntValue("foo")); - } - - @Test public void getIntValue_InvalidSetting() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getIntValue("foo")); } @Test public void getIntValue_InvalidType() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.getIntValue( HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE)); @@ -718,45 +376,7 @@ public final class HdmiCecConfigTest { Global.HDMI_CONTROL_ENABLED, Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED))) .thenReturn(Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED)); - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); - assertThat(hdmiCecConfig.getIntValue( - HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)) - .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); - } - - @Test - public void getIntValue_GlobalSetting_HexValue() { - when(mStorageAdapter.retrieveGlobalSetting( - Global.HDMI_CONTROL_ENABLED, - Integer.toHexString(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED))) - .thenReturn(Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED)); - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0x0\" />" - + " <value int-value=\"0x1\" />" - + " </allowed-values>" - + " <default-value int-value=\"0x1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)) .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); @@ -768,61 +388,23 @@ public final class HdmiCecConfigTest { HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_ENABLED))) .thenReturn(Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED)); - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"system_audio_mode_muting\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThat(hdmiCecConfig.getIntValue( HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING)) .isEqualTo(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED); } @Test - public void setStringValue_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThrows(IllegalArgumentException.class, - () -> hdmiCecConfig.setStringValue("foo", "bar")); - } - - @Test public void setStringValue_InvalidSetting() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.setStringValue("foo", "bar")); } @Test public void setStringValue_NotConfigurable() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"false\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + setBooleanResource(R.bool.config_cecSendStandbyOnSleep_userConfigurable, false); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.setStringValue( HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE, @@ -831,21 +413,7 @@ public final class HdmiCecConfigTest { @Test public void setStringValue_InvalidValue() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.setStringValue( HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE, @@ -854,21 +422,7 @@ public final class HdmiCecConfigTest { @Test public void setStringValue_GlobalSetting_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"send_standby_on_sleep\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"to_tv\" />" - + " <value string-value=\"broadcast\" />" - + " <value string-value=\"none\" />" - + " </allowed-values>" - + " <default-value string-value=\"to_tv\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); hdmiCecConfig.setStringValue(HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE, HdmiControlManager.POWER_CONTROL_MODE_BROADCAST); verify(mStorageAdapter).storeGlobalSetting( @@ -878,20 +432,7 @@ public final class HdmiCecConfigTest { @Test public void setStringValue_SharedPref_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"power_state_change_on_active_source_lost\"" - + " value-type=\"string\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value string-value=\"none\" />" - + " <value string-value=\"standby_now\" />" - + " </allowed-values>" - + " <default-value string-value=\"none\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); hdmiCecConfig.setStringValue( HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW); @@ -901,40 +442,16 @@ public final class HdmiCecConfigTest { } @Test - public void setIntValue_NoMasterXml() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, null, null); - assertThrows(IllegalArgumentException.class, - () -> hdmiCecConfig.setIntValue("foo", 0)); - } - - @Test public void setIntValue_InvalidSetting() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.setIntValue("foo", 0)); } @Test public void setIntValue_NotConfigurable() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"false\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + setBooleanResource(R.bool.config_cecHdmiCecEnabled_userConfigurable, false); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, @@ -943,20 +460,7 @@ public final class HdmiCecConfigTest { @Test public void setIntValue_InvalidValue() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); assertThrows(IllegalArgumentException.class, () -> hdmiCecConfig.setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, @@ -965,43 +469,7 @@ public final class HdmiCecConfigTest { @Test public void setIntValue_GlobalSetting_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); - hdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, - HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); - verify(mStorageAdapter).storeGlobalSetting( - Global.HDMI_CONTROL_ENABLED, - Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED)); - } - - @Test - public void setIntValue_GlobalSetting_HexValue() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0x0\" />" - + " <value int-value=\"0x1\" />" - + " </allowed-values>" - + " <default-value int-value=\"0x1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); hdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); verify(mStorageAdapter).storeGlobalSetting( @@ -1011,20 +479,7 @@ public final class HdmiCecConfigTest { @Test public void setIntValue_SharedPref_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"system_audio_mode_muting\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); hdmiCecConfig.setIntValue( HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED); @@ -1035,20 +490,7 @@ public final class HdmiCecConfigTest { @Test public void registerChangeListener_SharedPref_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"system_audio_mode_muting\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); hdmiCecConfig.registerChangeListener( HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, mSettingChangeListener); @@ -1061,20 +503,7 @@ public final class HdmiCecConfigTest { @Test public void removeChangeListener_SharedPref_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"system_audio_mode_muting\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); hdmiCecConfig.registerChangeListener( HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, mSettingChangeListener); @@ -1100,20 +529,7 @@ public final class HdmiCecConfigTest { String originalValue = Global.getString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED); try { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); + HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter); hdmiCecConfig.registerGlobalSettingsObserver(mTestLooper.getLooper()); HdmiCecConfig.SettingChangeListener latchUpdateListener = new HdmiCecConfig.SettingChangeListener() { 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 915392e6eb80..1a6bad8b29cf 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -61,6 +61,12 @@ import java.util.concurrent.TimeUnit; /** Tests for {@link HdmiCecLocalDevicePlayback} class. */ public class HdmiCecLocalDevicePlaybackTest { + private static final int PORT_1 = 1; + private static final HdmiDeviceInfo INFO_TV = new HdmiDeviceInfo( + ADDR_TV, 0x0000, PORT_1, HdmiDeviceInfo.DEVICE_TV, + 0x1234, "TV", + HdmiControlManager.POWER_STATUS_ON, HdmiControlManager.HDMI_CEC_VERSION_1_4_B); + private HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback; @@ -159,6 +165,7 @@ public class HdmiCecLocalDevicePlaybackTest { mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress); mTestLooper.dispatchAll(); mPlaybackLogicalAddress = mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(); + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); mNativeWrapper.clearResultMessages(); } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java new file mode 100644 index 000000000000..c61635cbd4b6 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java @@ -0,0 +1,464 @@ +/* + * 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.hdmi; + +import static com.android.server.hdmi.Constants.ADDR_TV; +import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; +import static com.android.server.hdmi.OneTouchPlayAction.STATE_WAITING_FOR_REPORT_POWER_STATUS; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.ContextWrapper; +import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.HdmiDeviceInfo; +import android.hardware.hdmi.IHdmiControlCallback; +import android.media.AudioManager; +import android.os.Handler; +import android.os.IPowerManager; +import android.os.IThermalService; +import android.os.Looper; +import android.os.PowerManager; +import android.os.test.TestLooper; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; + +import com.android.server.hdmi.HdmiCecFeatureAction.ActionTimer; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; + +/** Tests for {@link OneTouchPlayAction} */ +@SmallTest +@RunWith(JUnit4.class) +public class OneTouchPlayActionTest { + private static final byte[] POWER_ON = new byte[]{HdmiControlManager.POWER_STATUS_ON}; + private static final byte[] POWER_TRANSIENT_TO_ON = + new byte[]{HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON}; + + private static final int PORT_1 = 1; + private static final HdmiDeviceInfo INFO_TV = new HdmiDeviceInfo( + ADDR_TV, 0x0000, PORT_1, HdmiDeviceInfo.DEVICE_TV, + 0x1234, "TV", + HdmiControlManager.POWER_STATUS_ON, HdmiControlManager.HDMI_CEC_VERSION_1_4_B); + + private Context mContextSpy; + private HdmiControlService mHdmiControlService; + private FakeNativeWrapper mNativeWrapper; + + private TestLooper mTestLooper = new TestLooper(); + private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>(); + private int mPhysicalAddress; + + @Mock + private IPowerManager mIPowerManagerMock; + @Mock + private IThermalService mIThermalServiceMock; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); + + PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock, + mIThermalServiceMock, new Handler(mTestLooper.getLooper())); + when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager); + when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager); + when(mIPowerManagerMock.isInteractive()).thenReturn(true); + + mHdmiControlService = new HdmiControlService(mContextSpy) { + @Override + AudioManager getAudioManager() { + return new AudioManager() { + @Override + public void setWiredDeviceConnectionState( + int type, int state, String address, String name) { + // Do nothing. + } + }; + } + + @Override + void wakeUp() { + } + + @Override + boolean isPowerStandby() { + return false; + } + + @Override + protected PowerManager getPowerManager() { + return powerManager; + } + + @Override + protected void writeStringSystemProperty(String key, String value) { + // do nothing + } + }; + + Looper looper = mTestLooper.getLooper(); + mHdmiControlService.setIoLooper(looper); + mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy)); + mNativeWrapper = new FakeNativeWrapper(); + HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper( + this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); + mHdmiControlService.setCecController(hdmiCecController); + mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); + mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService)); + mHdmiControlService.initService(); + mPhysicalAddress = 0x2000; + mNativeWrapper.setPhysicalAddress(mPhysicalAddress); + mTestLooper.dispatchAll(); + } + + private OneTouchPlayAction createOneTouchPlayAction(HdmiCecLocalDevicePlayback device, + TestActionTimer actionTimer, TestCallback callback, boolean isCec20) { + OneTouchPlayAction action = new OneTouchPlayAction(device, ADDR_TV, callback, isCec20); + action.setActionTimer(actionTimer); + return action; + } + + @Test + public void succeedWithUnknownTvDevice() { + HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( + mHdmiControlService); + playbackDevice.init(); + mLocalDevices.add(playbackDevice); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mTestLooper.dispatchAll(); + + TestActionTimer actionTimer = new TestActionTimer(); + TestCallback callback = new TestCallback(); + OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback, + false); + playbackDevice.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( + playbackDevice.mAddress, mPhysicalAddress); + HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress, + ADDR_TV); + HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder + .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV); + + assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus); + mNativeWrapper.clearResultMessages(); + assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS); + HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage( + ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON); + action.processCommand(reportPowerStatusOn); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus); + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); + } + + @Test + public void succeedAfterGettingPowerStatusOn_Cec14b() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); + HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( + mHdmiControlService); + playbackDevice.init(); + mLocalDevices.add(playbackDevice); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mTestLooper.dispatchAll(); + + TestActionTimer actionTimer = new TestActionTimer(); + TestCallback callback = new TestCallback(); + OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback, + false); + playbackDevice.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( + playbackDevice.mAddress, mPhysicalAddress); + HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress, + ADDR_TV); + HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder + .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV); + + assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus); + mNativeWrapper.clearResultMessages(); + assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS); + HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage( + ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON); + action.processCommand(reportPowerStatusOn); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus); + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); + } + + @Test + public void succeedAfterGettingTransientPowerStatus_Cec14b() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); + HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( + mHdmiControlService); + playbackDevice.init(); + mLocalDevices.add(playbackDevice); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mTestLooper.dispatchAll(); + + TestActionTimer actionTimer = new TestActionTimer(); + TestCallback callback = new TestCallback(); + OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback, + false); + playbackDevice.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( + playbackDevice.mAddress, mPhysicalAddress); + HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress, + ADDR_TV); + HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder + .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV); + + assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus); + mNativeWrapper.clearResultMessages(); + assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS); + HdmiCecMessage reportPowerStatusTransientToOn = new HdmiCecMessage( + ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, + POWER_TRANSIENT_TO_ON); + action.processCommand(reportPowerStatusTransientToOn); + action.handleTimerEvent(STATE_WAITING_FOR_REPORT_POWER_STATUS); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus); + mNativeWrapper.clearResultMessages(); + + HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage( + ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON); + action.processCommand(reportPowerStatusOn); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus); + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); + } + + @Test + public void timeOut_Cec14b() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); + HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( + mHdmiControlService); + playbackDevice.init(); + mLocalDevices.add(playbackDevice); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mTestLooper.dispatchAll(); + + TestActionTimer actionTimer = new TestActionTimer(); + TestCallback callback = new TestCallback(); + OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback, + false); + playbackDevice.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( + playbackDevice.mAddress, mPhysicalAddress); + HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress, + ADDR_TV); + HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder + .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV); + + assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus); + mNativeWrapper.clearResultMessages(); + assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS); + for (int i = 0; i < 10; ++i) { + action.handleTimerEvent(STATE_WAITING_FOR_REPORT_POWER_STATUS); + mTestLooper.dispatchAll(); + } + + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSource); + assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus); + action.handleTimerEvent(STATE_WAITING_FOR_REPORT_POWER_STATUS); + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TIMEOUT); + } + + @Test + public void succeedIfPowerStatusOn_Cec20() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); + HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( + mHdmiControlService); + playbackDevice.init(); + mLocalDevices.add(playbackDevice); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV, + HdmiControlManager.POWER_STATUS_ON); + mTestLooper.dispatchAll(); + + TestActionTimer actionTimer = new TestActionTimer(); + TestCallback callback = new TestCallback(); + OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback, + true); + playbackDevice.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( + playbackDevice.mAddress, mPhysicalAddress); + HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress, + ADDR_TV); + HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder + .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV); + + assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus); + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); + } + + @Test + public void succeedIfPowerStatusUnknown_Cec20() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); + HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( + mHdmiControlService); + playbackDevice.init(); + mLocalDevices.add(playbackDevice); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV, + HdmiControlManager.POWER_STATUS_UNKNOWN); + mTestLooper.dispatchAll(); + + TestActionTimer actionTimer = new TestActionTimer(); + TestCallback callback = new TestCallback(); + OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback, + true); + playbackDevice.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( + playbackDevice.mAddress, mPhysicalAddress); + HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress, + ADDR_TV); + HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder + .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV); + + assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus); + mNativeWrapper.clearResultMessages(); + assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS); + HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage( + ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON); + action.processCommand(reportPowerStatusOn); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus); + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); + } + + @Test + public void succeedIfPowerStatusStandby_Cec20() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); + HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( + mHdmiControlService); + playbackDevice.init(); + mLocalDevices.add(playbackDevice); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV, + HdmiControlManager.POWER_STATUS_STANDBY); + mTestLooper.dispatchAll(); + + TestActionTimer actionTimer = new TestActionTimer(); + TestCallback callback = new TestCallback(); + OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback, + true); + playbackDevice.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( + playbackDevice.mAddress, mPhysicalAddress); + HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress, + ADDR_TV); + HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder + .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV); + + assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus); + mNativeWrapper.clearResultMessages(); + assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS); + HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage( + ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON); + action.processCommand(reportPowerStatusOn); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus); + assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); + } + + private static class TestActionTimer implements ActionTimer { + private int mState; + + @Override + public void sendTimerMessage(int state, long delayMillis) { + mState = state; + } + + @Override + public void clearTimerMessage() { + } + + private int getState() { + return mState; + } + } + + private static class TestCallback extends IHdmiControlCallback.Stub { + private final ArrayList<Integer> mCallbackResult = new ArrayList<Integer>(); + + @Override + public void onComplete(int result) { + mCallbackResult.add(result); + } + + private int getResult() { + assertThat(mCallbackResult.size()).isEqualTo(1); + return mCallbackResult.get(0); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java new file mode 100644 index 000000000000..865eb7a3b56d --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java @@ -0,0 +1,343 @@ +/* + * 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.hdmi; + + +import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM; +import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; +import static com.android.server.hdmi.SystemAudioAutoInitiationAction.RETRIES_ON_TIMEOUT; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.ContextWrapper; +import android.hardware.hdmi.HdmiPortInfo; +import android.media.AudioManager; +import android.os.Handler; +import android.os.IPowerManager; +import android.os.IThermalService; +import android.os.Looper; +import android.os.PowerManager; +import android.os.test.TestLooper; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; + +/** + * Test for {@link SystemAudioAutoInitiationAction}. + */ +@SmallTest +@RunWith(JUnit4.class) +public class SystemAudioAutoInitiationActionTest { + + private Context mContextSpy; + private HdmiControlService mHdmiControlService; + private FakeNativeWrapper mNativeWrapper; + + private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv; + + private TestLooper mTestLooper = new TestLooper(); + private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>(); + private int mPhysicalAddress; + + @Mock + private IPowerManager mIPowerManagerMock; + @Mock + private IThermalService mIThermalServiceMock; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); + + Looper myLooper = mTestLooper.getLooper(); + PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock, + mIThermalServiceMock, new Handler(myLooper)); + when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager); + when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager); + when(mIPowerManagerMock.isInteractive()).thenReturn(true); + + mHdmiControlService = new HdmiControlService(mContextSpy) { + @Override + AudioManager getAudioManager() { + return new AudioManager() { + @Override + public void setWiredDeviceConnectionState( + int type, int state, String address, String name) { + // Do nothing. + } + }; + } + + @Override + void wakeUp() { + } + + @Override + boolean isPowerStandby() { + return false; + } + + @Override + protected PowerManager getPowerManager() { + return powerManager; + } + + @Override + protected void writeStringSystemProperty(String key, String value) { + // do nothing + } + }; + + mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService); + mHdmiCecLocalDeviceTv.init(); + mHdmiControlService.setIoLooper(myLooper); + mNativeWrapper = new FakeNativeWrapper(); + HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper( + mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); + mHdmiControlService.setCecController(hdmiCecController); + mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); + mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService)); + mLocalDevices.add(mHdmiCecLocalDeviceTv); + HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[2]; + hdmiPortInfos[0] = + new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x1000, true, false, false); + hdmiPortInfos[1] = + new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, true); + mNativeWrapper.setPortInfo(hdmiPortInfos); + mHdmiControlService.initService(); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mPhysicalAddress = 0x0000; + mNativeWrapper.setPhysicalAddress(mPhysicalAddress); + mTestLooper.dispatchAll(); + mPhysicalAddress = mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(); + mNativeWrapper.clearResultMessages(); + } + + private void setSystemAudioSetting(boolean on) { + mHdmiCecLocalDeviceTv.setSystemAudioControlFeatureEnabled(on); + } + + private void setTvHasSystemAudioChangeAction() { + mHdmiCecLocalDeviceTv.addAndStartAction( + new SystemAudioActionFromTv(mHdmiCecLocalDeviceTv, Constants.ADDR_AUDIO_SYSTEM, + true, null)); + } + + @Test + public void testReceiveSystemAudioMode_systemAudioOn() { + // Record that previous system audio mode is on. + setSystemAudioSetting(true); + + HdmiCecFeatureAction action = new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, + ADDR_AUDIO_SYSTEM); + mHdmiCecLocalDeviceTv.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage giveSystemAudioModeStatus = + HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus( + mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM); + + assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus); + + HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode( + ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true); + mHdmiControlService.handleCecCommand(reportSystemAudioMode); + mTestLooper.dispatchAll(); + + assertThat(mHdmiControlService.isSystemAudioActivated()).isTrue(); + } + + @Test + public void testReceiveSystemAudioMode_systemAudioOnAndImpossibleToChangeSystemAudio() { + // Turn on system audio. + setSystemAudioSetting(true); + // Impossible to change system audio mode while SystemAudioActionFromTv is in progress. + setTvHasSystemAudioChangeAction(); + + HdmiCecFeatureAction action = new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, + ADDR_AUDIO_SYSTEM); + mHdmiCecLocalDeviceTv.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage giveSystemAudioModeStatus = + HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus( + mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM); + + assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus); + + HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode( + ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true); + mHdmiControlService.handleCecCommand(reportSystemAudioMode); + mTestLooper.dispatchAll(); + + assertThat(mHdmiControlService.isSystemAudioActivated()).isFalse(); + } + + @Test + public void testReceiveSystemAudioMode_systemAudioOnAndResponseOff() { + // Record that previous system audio mode is on. + setSystemAudioSetting(true); + + HdmiCecFeatureAction action = new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, + ADDR_AUDIO_SYSTEM); + mHdmiCecLocalDeviceTv.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage giveSystemAudioModeStatus = + HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus( + mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM); + + assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus); + + HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode( + ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, false); + mHdmiControlService.handleCecCommand(reportSystemAudioMode); + mTestLooper.dispatchAll(); + + assertThat(mHdmiCecLocalDeviceTv.getActions(SystemAudioActionFromTv.class)).isNotEmpty(); + SystemAudioActionFromTv resultingAction = mHdmiCecLocalDeviceTv.getActions( + SystemAudioActionFromTv.class).get(0); + assertThat(resultingAction.mTargetAudioStatus).isTrue(); + } + + @Test + public void testReceiveSystemAudioMode_settingOffAndResponseOn() { + // Turn off system audio. + setSystemAudioSetting(false); + + HdmiCecFeatureAction action = new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, + ADDR_AUDIO_SYSTEM); + mHdmiCecLocalDeviceTv.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage giveSystemAudioModeStatus = + HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus( + mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM); + + assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus); + + HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode( + ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true); + mHdmiControlService.handleCecCommand(reportSystemAudioMode); + mTestLooper.dispatchAll(); + + assertThat(mHdmiCecLocalDeviceTv.getActions(SystemAudioActionFromTv.class)).isNotEmpty(); + SystemAudioActionFromTv resultingAction = mHdmiCecLocalDeviceTv.getActions( + SystemAudioActionFromTv.class).get(0); + assertThat(resultingAction.mTargetAudioStatus).isFalse(); + } + + @Test + public void testReceiveSystemAudioMode_settingOffAndResponseOff() { + // Turn off system audio. + setSystemAudioSetting(false); + + HdmiCecFeatureAction action = new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, + ADDR_AUDIO_SYSTEM); + mHdmiCecLocalDeviceTv.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage giveSystemAudioModeStatus = + HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus( + mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM); + + assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus); + + HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode( + ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, false); + mHdmiControlService.handleCecCommand(reportSystemAudioMode); + mTestLooper.dispatchAll(); + + assertThat(mHdmiCecLocalDeviceTv.getActions(SystemAudioActionFromTv.class)).isEmpty(); + assertThat(mHdmiControlService.isSystemAudioActivated()).isFalse(); + } + + @Test + public void testTimeout_systemAudioOn_retries() { + // Turn on system audio. + setSystemAudioSetting(true); + + HdmiCecFeatureAction action = new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, + ADDR_AUDIO_SYSTEM); + mHdmiCecLocalDeviceTv.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage giveSystemAudioModeStatus = + HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus( + mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM); + + assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus); + mNativeWrapper.clearResultMessages(); + + mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); + mTestLooper.dispatchAll(); + + // Retry sends <Give System Audio Mode Status> again + assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus); + } + + @Test + public void testTimeout_systemAudioOn_allRetriesFail() { + boolean targetStatus = true; + // Turn on system audio. + setSystemAudioSetting(targetStatus); + + HdmiCecFeatureAction action = new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, + ADDR_AUDIO_SYSTEM); + mHdmiCecLocalDeviceTv.addAndStartAction(action); + mTestLooper.dispatchAll(); + + HdmiCecMessage giveSystemAudioModeStatus = + HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus( + mHdmiCecLocalDeviceTv.mAddress, ADDR_AUDIO_SYSTEM); + assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus); + + for (int i = 0; i < RETRIES_ON_TIMEOUT; i++) { + mNativeWrapper.clearResultMessages(); + + // Target device doesn't respond within timeout + mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); + mTestLooper.dispatchAll(); + + // Retry sends <Give System Audio Mode Status> again + assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus); + } + + // Target device doesn't respond within timeouts + mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); + mTestLooper.dispatchAll(); + + assertThat(mHdmiCecLocalDeviceTv.getActions(SystemAudioActionFromTv.class)).isNotEmpty(); + SystemAudioActionFromTv resultingAction = mHdmiCecLocalDeviceTv.getActions( + SystemAudioActionFromTv.class).get(0); + assertThat(resultingAction.mTargetAudioStatus).isEqualTo(targetStatus); + } +} diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java index 1db5544871bf..d07831dd7929 100644 --- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java @@ -11,15 +11,15 @@ * 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. */ package com.android.server.inputmethod; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; -import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; +import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java index 6ab48e53648c..9092ec325946 100644 --- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java @@ -177,10 +177,10 @@ public class InputMethodSubtypeSwitchingControllerTest { private void assertRotationOrder(final ControllerImpl controller, final boolean onlyCurrentIme, final ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) { - final int N = expectedRotationOrderOfImeSubtypeList.length; - for (int i = 0; i < N; i++) { + final int numItems = expectedRotationOrderOfImeSubtypeList.length; + for (int i = 0; i < numItems; i++) { final int currentIndex = i; - final int nextIndex = (currentIndex + 1) % N; + final int nextIndex = (currentIndex + 1) % numItems; final ImeSubtypeListItem currentItem = expectedRotationOrderOfImeSubtypeList[currentIndex]; final ImeSubtypeListItem nextItem = expectedRotationOrderOfImeSubtypeList[nextIndex]; @@ -200,47 +200,47 @@ public class InputMethodSubtypeSwitchingControllerTest { @Test public void testControllerImpl() throws Exception { final List<ImeSubtypeListItem> disabledItems = createDisabledImeSubtypes(); - final ImeSubtypeListItem disabledIme_en_US = disabledItems.get(0); + final ImeSubtypeListItem disabledIme_en_us = disabledItems.get(0); final ImeSubtypeListItem disabledIme_hi = disabledItems.get(1); final ImeSubtypeListItem disabledSwitchingUnawareIme = disabledItems.get(2); final ImeSubtypeListItem disabledSubtypeUnawareIme = disabledItems.get(3); final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes(); - final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0); + final ImeSubtypeListItem latinIme_en_us = enabledItems.get(0); final ImeSubtypeListItem latinIme_fr = enabledItems.get(1); - final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2); - final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3); + final ImeSubtypeListItem switchingUnawareLatinIme_en_uk = enabledItems.get(2); + final ImeSubtypeListItem switchingUnawareLatinIme_hi = enabledItems.get(3); final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4); - final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5); - final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6); + final ImeSubtypeListItem japaneseIme_ja_jp = enabledItems.get(5); + final ImeSubtypeListItem switchUnawareJapaneseIme_ja_jp = enabledItems.get(6); final ControllerImpl controller = ControllerImpl.createFrom( null /* currentInstance */, enabledItems); // switching-aware loop assertRotationOrder(controller, false /* onlyCurrentIme */, - latinIme_en_US, latinIme_fr, japaneseIme_ja_JP); + latinIme_en_us, latinIme_fr, japaneseIme_ja_jp); // switching-unaware loop assertRotationOrder(controller, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, - switchUnawareJapaneseIme_ja_JP); + switchingUnawareLatinIme_en_uk, switchingUnawareLatinIme_hi, subtypeUnawareIme, + switchUnawareJapaneseIme_ja_jp); // test onlyCurrentIme == true assertRotationOrder(controller, true /* onlyCurrentIme */, - latinIme_en_US, latinIme_fr); + latinIme_en_us, latinIme_fr); assertRotationOrder(controller, true /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi); + switchingUnawareLatinIme_en_uk, switchingUnawareLatinIme_hi); assertNextInputMethod(controller, true /* onlyCurrentIme */, subtypeUnawareIme, null); assertNextInputMethod(controller, true /* onlyCurrentIme */, - japaneseIme_ja_JP, null); + japaneseIme_ja_jp, null); assertNextInputMethod(controller, true /* onlyCurrentIme */, - switchUnawareJapaneseIme_ja_JP, null); + switchUnawareJapaneseIme_ja_jp, null); // Make sure that disabled IMEs are not accepted. assertNextInputMethod(controller, false /* onlyCurrentIme */, - disabledIme_en_US, null); + disabledIme_en_us, null); assertNextInputMethod(controller, false /* onlyCurrentIme */, disabledIme_hi, null); assertNextInputMethod(controller, false /* onlyCurrentIme */, @@ -248,7 +248,7 @@ public class InputMethodSubtypeSwitchingControllerTest { assertNextInputMethod(controller, false /* onlyCurrentIme */, disabledSubtypeUnawareIme, null); assertNextInputMethod(controller, true /* onlyCurrentIme */, - disabledIme_en_US, null); + disabledIme_en_us, null); assertNextInputMethod(controller, true /* onlyCurrentIme */, disabledIme_hi, null); assertNextInputMethod(controller, true /* onlyCurrentIme */, @@ -260,82 +260,82 @@ public class InputMethodSubtypeSwitchingControllerTest { @Test public void testControllerImplWithUserAction() throws Exception { final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes(); - final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0); + final ImeSubtypeListItem latinIme_en_us = enabledItems.get(0); final ImeSubtypeListItem latinIme_fr = enabledItems.get(1); - final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2); + final ImeSubtypeListItem switchingUnawarelatinIme_en_uk = enabledItems.get(2); final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3); final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4); - final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5); - final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6); + final ImeSubtypeListItem japaneseIme_ja_jp = enabledItems.get(5); + final ImeSubtypeListItem switchUnawareJapaneseIme_ja_jp = enabledItems.get(6); final ControllerImpl controller = ControllerImpl.createFrom( null /* currentInstance */, enabledItems); // === switching-aware loop === assertRotationOrder(controller, false /* onlyCurrentIme */, - latinIme_en_US, latinIme_fr, japaneseIme_ja_JP); + latinIme_en_us, latinIme_fr, japaneseIme_ja_jp); // Then notify that a user did something for latinIme_fr. onUserAction(controller, latinIme_fr); assertRotationOrder(controller, false /* onlyCurrentIme */, - latinIme_fr, latinIme_en_US, japaneseIme_ja_JP); + latinIme_fr, latinIme_en_us, japaneseIme_ja_jp); // Then notify that a user did something for latinIme_fr again. onUserAction(controller, latinIme_fr); assertRotationOrder(controller, false /* onlyCurrentIme */, - latinIme_fr, latinIme_en_US, japaneseIme_ja_JP); + latinIme_fr, latinIme_en_us, japaneseIme_ja_jp); // Then notify that a user did something for japaneseIme_ja_JP. onUserAction(controller, latinIme_fr); assertRotationOrder(controller, false /* onlyCurrentIme */, - japaneseIme_ja_JP, latinIme_fr, latinIme_en_US); + japaneseIme_ja_jp, latinIme_fr, latinIme_en_us); // Check onlyCurrentIme == true. assertNextInputMethod(controller, true /* onlyCurrentIme */, - japaneseIme_ja_JP, null); + japaneseIme_ja_jp, null); assertRotationOrder(controller, true /* onlyCurrentIme */, - latinIme_fr, latinIme_en_US); + latinIme_fr, latinIme_en_us); assertRotationOrder(controller, true /* onlyCurrentIme */, - latinIme_en_US, latinIme_fr); + latinIme_en_us, latinIme_fr); // === switching-unaware loop === assertRotationOrder(controller, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, - switchUnawareJapaneseIme_ja_JP); + switchingUnawarelatinIme_en_uk, switchingUnawarelatinIme_hi, subtypeUnawareIme, + switchUnawareJapaneseIme_ja_jp); // User action should be ignored for switching unaware IMEs. onUserAction(controller, switchingUnawarelatinIme_hi); assertRotationOrder(controller, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, - switchUnawareJapaneseIme_ja_JP); + switchingUnawarelatinIme_en_uk, switchingUnawarelatinIme_hi, subtypeUnawareIme, + switchUnawareJapaneseIme_ja_jp); // User action should be ignored for switching unaware IMEs. - onUserAction(controller, switchUnawareJapaneseIme_ja_JP); + onUserAction(controller, switchUnawareJapaneseIme_ja_jp); assertRotationOrder(controller, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, - switchUnawareJapaneseIme_ja_JP); + switchingUnawarelatinIme_en_uk, switchingUnawarelatinIme_hi, subtypeUnawareIme, + switchUnawareJapaneseIme_ja_jp); // Check onlyCurrentIme == true. assertRotationOrder(controller, true /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi); + switchingUnawarelatinIme_en_uk, switchingUnawarelatinIme_hi); assertNextInputMethod(controller, true /* onlyCurrentIme */, subtypeUnawareIme, null); assertNextInputMethod(controller, true /* onlyCurrentIme */, - switchUnawareJapaneseIme_ja_JP, null); + switchUnawareJapaneseIme_ja_jp, null); // Rotation order should be preserved when created with the same subtype list. final List<ImeSubtypeListItem> sameEnabledItems = createEnabledImeSubtypes(); final ControllerImpl newController = ControllerImpl.createFrom(controller, sameEnabledItems); assertRotationOrder(newController, false /* onlyCurrentIme */, - japaneseIme_ja_JP, latinIme_fr, latinIme_en_US); + japaneseIme_ja_jp, latinIme_fr, latinIme_en_us); assertRotationOrder(newController, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, - switchUnawareJapaneseIme_ja_JP); + switchingUnawarelatinIme_en_uk, switchingUnawarelatinIme_hi, subtypeUnawareIme, + switchUnawareJapaneseIme_ja_jp); // Rotation order should be initialized when created with a different subtype list. final List<ImeSubtypeListItem> differentEnabledItems = Arrays.asList( - latinIme_en_US, latinIme_fr, switchingUnawarelatinIme_en_UK, - switchUnawareJapaneseIme_ja_JP); + latinIme_en_us, latinIme_fr, switchingUnawarelatinIme_en_uk, + switchUnawareJapaneseIme_ja_jp); final ControllerImpl anotherController = ControllerImpl.createFrom(controller, differentEnabledItems); assertRotationOrder(anotherController, false /* onlyCurrentIme */, - latinIme_en_US, latinIme_fr); + latinIme_en_us, latinIme_fr); assertRotationOrder(anotherController, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchUnawareJapaneseIme_ja_JP); + switchingUnawarelatinIme_en_uk, switchUnawareJapaneseIme_ja_jp); } @Test @@ -344,27 +344,27 @@ public class InputMethodSubtypeSwitchingControllerTest { addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme", Arrays.asList("en_US", "fr", "en", "en_uk", "enn", "e", "EN_US"), true /* supportsSwitchingToNextInputMethod*/); - final ImeSubtypeListItem item_en_US = items.get(0); + final ImeSubtypeListItem item_en_us = items.get(0); final ImeSubtypeListItem item_fr = items.get(1); final ImeSubtypeListItem item_en = items.get(2); final ImeSubtypeListItem item_enn = items.get(3); final ImeSubtypeListItem item_e = items.get(4); - final ImeSubtypeListItem item_EN_US = items.get(5); + final ImeSubtypeListItem item_en_us_allcaps = items.get(5); - assertTrue(item_en_US.mIsSystemLocale); + assertTrue(item_en_us.mIsSystemLocale); assertFalse(item_fr.mIsSystemLocale); assertFalse(item_en.mIsSystemLocale); assertFalse(item_en.mIsSystemLocale); assertFalse(item_enn.mIsSystemLocale); assertFalse(item_e.mIsSystemLocale); - assertFalse(item_EN_US.mIsSystemLocale); + assertFalse(item_en_us_allcaps.mIsSystemLocale); - assertTrue(item_en_US.mIsSystemLanguage); + assertTrue(item_en_us.mIsSystemLanguage); assertFalse(item_fr.mIsSystemLanguage); assertTrue(item_en.mIsSystemLanguage); assertFalse(item_enn.mIsSystemLocale); assertFalse(item_e.mIsSystemLocale); - assertFalse(item_EN_US.mIsSystemLocale); + assertFalse(item_en_us_allcaps.mIsSystemLocale); } @Test diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java index 1d914ec083fa..eebc25aab279 100644 --- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java @@ -60,6 +60,7 @@ public class InputMethodUtilsTest { private static final boolean IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE = true; private static final boolean IS_ASCII_CAPABLE = true; private static final boolean IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE = true; + private static final boolean CHECK_COUNTRY = true; private static final Locale LOCALE_EN = new Locale("en"); private static final Locale LOCALE_EN_US = new Locale("en", "US"); private static final Locale LOCALE_EN_GB = new Locale("en", "GB"); @@ -668,8 +669,6 @@ public class InputMethodUtilsTest { SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final boolean CHECK_COUNTRY = true; - { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoEnUS); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java index b51f4df43259..91342ce925f6 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; @@ -109,7 +110,8 @@ public class RebootEscrowManagerTests { public interface MockableRebootEscrowInjected { int getBootCount(); - void reportMetric(boolean success); + void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, + int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete); } static class MockInjector extends RebootEscrowManager.Injector { @@ -119,6 +121,7 @@ public class RebootEscrowManagerTests { private final UserManager mUserManager; private final MockableRebootEscrowInjected mInjected; private final RebootEscrowKeyStoreManager mKeyStoreManager; + private final boolean mServerBased; MockInjector(Context context, UserManager userManager, IRebootEscrow rebootEscrow, @@ -128,6 +131,7 @@ public class RebootEscrowManagerTests { super(context, storage); mRebootEscrow = rebootEscrow; mServiceConnection = null; + mServerBased = false; RebootEscrowProviderHalImpl.Injector halInjector = new RebootEscrowProviderHalImpl.Injector() { @Override @@ -149,6 +153,7 @@ public class RebootEscrowManagerTests { super(context, storage); mServiceConnection = serviceConnection; mRebootEscrow = null; + mServerBased = true; RebootEscrowProviderServerBasedImpl.Injector injector = new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection); mRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(storage, injector); @@ -168,6 +173,11 @@ public class RebootEscrowManagerTests { } @Override + public boolean serverBasedResumeOnReboot() { + return mServerBased; + } + + @Override public RebootEscrowProviderInterface getRebootEscrowProvider() { return mRebootEscrowProvider; } @@ -195,8 +205,11 @@ public class RebootEscrowManagerTests { } @Override - public void reportMetric(boolean success) { - mInjected.reportMetric(success); + public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, + int escrowDurationInSeconds, int vbmetaDigestStatus, + int durationSinceBootComplete) { + mInjected.reportMetric(success, errorCode, serviceType, attemptCount, + escrowDurationInSeconds, vbmetaDigestStatus, durationSinceBootComplete); } } @@ -418,7 +431,9 @@ public class RebootEscrowManagerTests { when(mInjected.getBootCount()).thenReturn(1); ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); - doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture()); + doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(), + eq(0) /* error code */, eq(1) /* HAL based */, eq(1) /* attempt count */, + anyInt(), anyInt(), anyInt()); when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue()); mService.loadRebootEscrowDataIfAvailable(null); @@ -451,7 +466,9 @@ public class RebootEscrowManagerTests { // pretend reboot happens here when(mInjected.getBootCount()).thenReturn(1); ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); - doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture()); + doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(), + eq(0) /* error code */, eq(2) /* Server based */, eq(1) /* attempt count */, + anyInt(), anyInt(), anyInt()); when(mServiceConnection.unwrap(any(), anyLong())) .thenAnswer(invocation -> invocation.getArgument(0)); @@ -485,7 +502,8 @@ public class RebootEscrowManagerTests { // pretend reboot happens here when(mInjected.getBootCount()).thenReturn(1); ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); - doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture()); + doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(), + anyInt(), anyInt(), eq(2) /* attempt count */, anyInt(), anyInt(), anyInt()); when(mServiceConnection.unwrap(any(), anyLong())) .thenThrow(new IOException()) @@ -528,7 +546,8 @@ public class RebootEscrowManagerTests { mService.loadRebootEscrowDataIfAvailable(null); verify(mRebootEscrow).retrieveKey(); - verify(mInjected, never()).reportMetric(anyBoolean()); + verify(mInjected, never()).reportMetric(anyBoolean(), anyInt(), anyInt(), anyInt(), + anyInt(), anyInt(), anyInt()); } @Test @@ -554,7 +573,8 @@ public class RebootEscrowManagerTests { when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]); mService.loadRebootEscrowDataIfAvailable(null); - verify(mInjected, never()).reportMetric(anyBoolean()); + verify(mInjected, never()).reportMetric(anyBoolean(), anyInt(), anyInt(), anyInt(), + anyInt(), anyInt(), anyInt()); } @Test @@ -588,7 +608,8 @@ public class RebootEscrowManagerTests { when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue()); mService.loadRebootEscrowDataIfAvailable(null); - verify(mInjected).reportMetric(eq(true)); + verify(mInjected).reportMetric(eq(true), eq(0) /* error code */, eq(1) /* HAL based */, + eq(1) /* attempt count */, anyInt(), anyInt(), anyInt()); } @Test @@ -615,7 +636,9 @@ public class RebootEscrowManagerTests { when(mInjected.getBootCount()).thenReturn(1); ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); - doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture()); + doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(), + anyInt() /* error code */, eq(1) /* HAL based */, eq(1) /* attempt count */, + anyInt(), anyInt(), anyInt()); when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> new byte[32]); mService.loadRebootEscrowDataIfAvailable(null); verify(mRebootEscrow).retrieveKey(); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java index dd3054f6543c..3fd2c97075ac 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java @@ -32,7 +32,6 @@ import android.app.KeyguardManager; import android.content.Context; import android.os.RemoteException; import android.security.GateKeeper; -import android.security.keystore.AndroidKeyStoreSecretKey; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; @@ -59,6 +58,7 @@ import java.security.UnrecoverableKeyException; import java.util.List; import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; @SmallTest @RunWith(AndroidJUnit4.class) @@ -575,7 +575,7 @@ public class PlatformKeyManagerTest { return (KeyProtection) mProtectionParameterCaptor.getValue(); } - private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception { + private SecretKey generateAndroidKeyStoreKey() throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance( KEY_ALGORITHM, ANDROID_KEY_STORE_PROVIDER); @@ -584,7 +584,7 @@ public class PlatformKeyManagerTest { .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .build()); - return (AndroidKeyStoreSecretKey) keyGenerator.generateKey(); + return keyGenerator.generateKey(); } class PlatformKeyManagerTestable extends PlatformKeyManager { diff --git a/services/tests/servicestests/src/com/android/server/rotationresolver/RotationResolverManagerPerUserServiceTest.java b/services/tests/servicestests/src/com/android/server/rotationresolver/RotationResolverManagerPerUserServiceTest.java index 22c38c1961b8..fa2123c0d09a 100644 --- a/services/tests/servicestests/src/com/android/server/rotationresolver/RotationResolverManagerPerUserServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/rotationresolver/RotationResolverManagerPerUserServiceTest.java @@ -31,6 +31,7 @@ import android.content.pm.ServiceInfo; import android.os.CancellationSignal; import android.os.RemoteException; import android.rotationresolver.RotationResolverInternal; +import android.service.rotationresolver.RotationResolutionRequest; import android.view.Surface; import androidx.test.core.app.ApplicationProvider; @@ -58,6 +59,7 @@ public class RotationResolverManagerPerUserServiceTest { private Context mContext; private CancellationSignal mCancellationSignal; private RotationResolverManagerPerUserService mService; + private RotationResolutionRequest mRequest; @Before public void setUp() throws RemoteException { @@ -79,9 +81,10 @@ public class RotationResolverManagerPerUserServiceTest { mCancellationSignal = new CancellationSignal(); + mRequest = new RotationResolutionRequest("", Surface.ROTATION_0, Surface.ROTATION_0, + true, 1000L); this.mService.mCurrentRequest = new RemoteRotationResolverService.RotationRequest( - mMockCallbackInternal, Surface.ROTATION_0, Surface.ROTATION_0, "", 1000L, - mCancellationSignal); + mMockCallbackInternal, mRequest, mCancellationSignal); this.mService.getMaster().mIsServiceEnabled = true; @@ -99,8 +102,7 @@ public class RotationResolverManagerPerUserServiceTest { RotationResolverInternal.RotationResolverCallbackInternal callbackInternal = Mockito.mock(RotationResolverInternal.RotationResolverCallbackInternal.class); - mService.resolveRotationLocked(callbackInternal, Surface.ROTATION_0, Surface.ROTATION_0, - "", 1000L, mCancellationSignal); + mService.resolveRotationLocked(callbackInternal, mRequest, mCancellationSignal); verify(callbackInternal).onSuccess(anyInt()); } @@ -110,8 +112,7 @@ public class RotationResolverManagerPerUserServiceTest { Mockito.mock(RotationResolverInternal.RotationResolverCallbackInternal.class); final CancellationSignal cancellationSignal = new CancellationSignal(); - mService.resolveRotationLocked(callbackInternal, Surface.ROTATION_0, Surface.ROTATION_0, - "", 1000L, cancellationSignal); + mService.resolveRotationLocked(callbackInternal, mRequest, cancellationSignal); cancellationSignal.cancel(); } @@ -132,7 +133,7 @@ public class RotationResolverManagerPerUserServiceTest { @Override public void resolveRotationLocked(RotationRequest request) { - request.mCallbackInternal.onSuccess(request.mProposedRotation); + request.mCallbackInternal.onSuccess(request.mRemoteRequest.getProposedRotation()); } } } diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java index 5f86d282406a..bbf11fd557a3 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java @@ -209,7 +209,7 @@ public class TimeDetectorServiceTest { @Test(expected = SecurityException.class) public void testSuggestExternalTime_withoutPermission() { doThrow(new SecurityException("Mock")) - .when(mMockContext).enforceCallingOrSelfPermission(anyString(), any()); + .when(mMockContext).enforceCallingPermission(anyString(), any()); ExternalTimeSuggestion externalTimeSuggestion = createExternalTimeSuggestion(); try { diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java index 5d2755221288..00369829db56 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java @@ -46,7 +46,7 @@ public class ConfigurationInternalTest { public void test_unrestricted() { ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionFeatureSupported(true) + .setTelephonyDetectionFeatureSupported(true) .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(true) .setLocationEnabled(true) @@ -108,7 +108,7 @@ public class ConfigurationInternalTest { public void test_restricted() { ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID) .setUserConfigAllowed(false) - .setAutoDetectionFeatureSupported(true) + .setTelephonyDetectionFeatureSupported(true) .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(true) .setLocationEnabled(true) @@ -170,7 +170,7 @@ public class ConfigurationInternalTest { public void test_autoDetectNotSupported() { ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionFeatureSupported(false) + .setTelephonyDetectionFeatureSupported(false) .setGeoDetectionFeatureSupported(false) .setAutoDetectionEnabled(true) .setLocationEnabled(true) @@ -232,7 +232,7 @@ public class ConfigurationInternalTest { public void test_geoDetectNotSupported() { ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionFeatureSupported(true) + .setTelephonyDetectionFeatureSupported(true) .setGeoDetectionFeatureSupported(false) .setAutoDetectionEnabled(true) .setLocationEnabled(true) diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java index 14e0bbd6fa42..8af2c4d04fd9 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java @@ -364,7 +364,7 @@ public class TimeZoneDetectorServiceTest { // the tests. final boolean geoDetectionEnabled = autoDetectionEnabled; return new ConfigurationInternal.Builder(ARBITRARY_USER_ID) - .setAutoDetectionFeatureSupported(true) + .setTelephonyDetectionFeatureSupported(true) .setGeoDetectionFeatureSupported(true) .setUserConfigAllowed(true) .setAutoDetectionEnabled(autoDetectionEnabled) diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java index f1f8b2f5e81a..b0341d7d67d5 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java @@ -90,7 +90,7 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED = new ConfigurationInternal.Builder(USER_ID) .setUserConfigAllowed(false) - .setAutoDetectionFeatureSupported(true) + .setTelephonyDetectionFeatureSupported(true) .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(false) .setLocationEnabled(true) @@ -100,7 +100,7 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED = new ConfigurationInternal.Builder(USER_ID) .setUserConfigAllowed(false) - .setAutoDetectionFeatureSupported(true) + .setTelephonyDetectionFeatureSupported(true) .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(true) .setLocationEnabled(true) @@ -110,17 +110,17 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED = new ConfigurationInternal.Builder(USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionFeatureSupported(false) + .setTelephonyDetectionFeatureSupported(false) .setGeoDetectionFeatureSupported(false) .setAutoDetectionEnabled(false) .setLocationEnabled(true) .setGeoDetectionEnabled(false) .build(); - private static final ConfigurationInternal CONFIG_INT_AUTO_SUPPORTED_GEO_NOT_SUPPORTED = + private static final ConfigurationInternal CONFIG_INT_TELEPHONY_SUPPORTED_GEO_NOT_SUPPORTED = new ConfigurationInternal.Builder(USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionFeatureSupported(true) + .setTelephonyDetectionFeatureSupported(true) .setGeoDetectionFeatureSupported(false) .setAutoDetectionEnabled(true) .setLocationEnabled(true) @@ -130,7 +130,7 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_DISABLED = new ConfigurationInternal.Builder(USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionFeatureSupported(true) + .setTelephonyDetectionFeatureSupported(true) .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(false) .setLocationEnabled(true) @@ -139,7 +139,7 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_DISABLED = new ConfigurationInternal.Builder(USER_ID) - .setAutoDetectionFeatureSupported(true) + .setTelephonyDetectionFeatureSupported(true) .setGeoDetectionFeatureSupported(true) .setUserConfigAllowed(true) .setAutoDetectionEnabled(true) @@ -149,7 +149,7 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_ENABLED = new ConfigurationInternal.Builder(USER_ID) - .setAutoDetectionFeatureSupported(true) + .setTelephonyDetectionFeatureSupported(true) .setGeoDetectionFeatureSupported(true) .setUserConfigAllowed(true) .setAutoDetectionEnabled(true) @@ -266,7 +266,8 @@ public class TimeZoneDetectorStrategyImplTest { @Test public void testUpdateConfiguration_autoDetectSupportedGeoNotSupported() { - Script script = new Script().initializeConfig(CONFIG_INT_AUTO_SUPPORTED_GEO_NOT_SUPPORTED); + Script script = new Script().initializeConfig( + CONFIG_INT_TELEPHONY_SUPPORTED_GEO_NOT_SUPPORTED); // Update the configuration with auto detection disabled. script.simulateUpdateConfiguration( @@ -274,7 +275,7 @@ public class TimeZoneDetectorStrategyImplTest { // The settings should have been changed and the StrategyListener onChange() called. ConfigurationInternal expectedConfig = - new ConfigurationInternal.Builder(CONFIG_INT_AUTO_SUPPORTED_GEO_NOT_SUPPORTED) + new ConfigurationInternal.Builder(CONFIG_INT_TELEPHONY_SUPPORTED_GEO_NOT_SUPPORTED) .setAutoDetectionEnabled(false) .build(); script.verifyConfigurationChangedAndReset(expectedConfig); @@ -675,6 +676,8 @@ public class TimeZoneDetectorStrategyImplTest { script.simulateManualTimeZoneSuggestion( USER_ID, createManualSuggestion("Europe/Paris"), false /* expectedResult */) .verifyTimeZoneNotChanged(); + + assertNull(mTimeZoneDetectorStrategy.getLatestManualSuggestion()); } @Test @@ -687,6 +690,8 @@ public class TimeZoneDetectorStrategyImplTest { script.simulateManualTimeZoneSuggestion( USER_ID, createManualSuggestion("Europe/Paris"), false /* expectedResult */) .verifyTimeZoneNotChanged(); + + assertNull(mTimeZoneDetectorStrategy.getLatestManualSuggestion()); } @Test @@ -700,6 +705,8 @@ public class TimeZoneDetectorStrategyImplTest { script.simulateManualTimeZoneSuggestion( USER_ID, manualSuggestion, true /* expectedResult */) .verifyTimeZoneChangedAndReset(manualSuggestion); + + assertEquals(manualSuggestion, mTimeZoneDetectorStrategy.getLatestManualSuggestion()); } @Test @@ -713,6 +720,8 @@ public class TimeZoneDetectorStrategyImplTest { script.simulateManualTimeZoneSuggestion( USER_ID, manualSuggestion, false /* expectedResult */) .verifyTimeZoneNotChanged(); + + assertNull(mTimeZoneDetectorStrategy.getLatestManualSuggestion()); } @Test @@ -726,6 +735,8 @@ public class TimeZoneDetectorStrategyImplTest { script.simulateManualTimeZoneSuggestion( USER_ID, manualSuggestion, true /* expectedResult */) .verifyTimeZoneChangedAndReset(manualSuggestion); + + assertEquals(manualSuggestion, mTimeZoneDetectorStrategy.getLatestManualSuggestion()); } @Test diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java index 4284240c72b4..3daa7f0483c6 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java @@ -72,6 +72,7 @@ public class ControllerImplTest { private TestCallback mTestCallback; private TestLocationTimeZoneProvider mTestPrimaryLocationTimeZoneProvider; private TestLocationTimeZoneProvider mTestSecondaryLocationTimeZoneProvider; + private FakeTimeZoneIdValidator mTimeZoneAvailabilityChecker; @Before public void setUp() { @@ -80,10 +81,13 @@ public class ControllerImplTest { // will never get a chance to execute. mTestThreadingDomain = new TestThreadingDomain(); mTestCallback = new TestCallback(mTestThreadingDomain); + mTimeZoneAvailabilityChecker = new FakeTimeZoneIdValidator(); mTestPrimaryLocationTimeZoneProvider = - new TestLocationTimeZoneProvider(mTestThreadingDomain, "primary"); + new TestLocationTimeZoneProvider( + mTestThreadingDomain, "primary", mTimeZoneAvailabilityChecker); mTestSecondaryLocationTimeZoneProvider = - new TestLocationTimeZoneProvider(mTestThreadingDomain, "secondary"); + new TestLocationTimeZoneProvider( + mTestThreadingDomain, "secondary", mTimeZoneAvailabilityChecker); } @Test @@ -1177,8 +1181,10 @@ public class ControllerImplTest { /** * Creates the instance. */ - TestLocationTimeZoneProvider(ThreadingDomain threadingDomain, String providerName) { - super(threadingDomain, providerName); + TestLocationTimeZoneProvider(ThreadingDomain threadingDomain, + String providerName, + TimeZoneIdValidator timeZoneIdValidator) { + super(threadingDomain, providerName, timeZoneIdValidator); } public void setFailDuringInitialization(boolean failInitialization) { @@ -1311,4 +1317,14 @@ public class ControllerImplTest { mTestProviderState.commitLatest(); } } + + private static final class FakeTimeZoneIdValidator + implements LocationTimeZoneProvider.TimeZoneIdValidator { + + @Override + public boolean isValid(@NonNull String timeZoneId) { + return true; + } + + } } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java index 095c868fc74c..278fdaff260f 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java @@ -32,6 +32,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static java.util.Arrays.asList; + import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Bundle; @@ -50,7 +52,9 @@ import org.junit.Test; import java.time.Duration; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicReference; /** @@ -62,20 +66,25 @@ public class LocationTimeZoneProviderTest { private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 123456789L; private TestThreadingDomain mTestThreadingDomain; - private TestProviderListener mProviderListener; + private FakeTimeZoneIdValidator mTimeZoneAvailabilityChecker; @Before public void setUp() { mTestThreadingDomain = new TestThreadingDomain(); mProviderListener = new TestProviderListener(); + mTimeZoneAvailabilityChecker = new FakeTimeZoneIdValidator(); } @Test public void lifecycle() { String providerName = "arbitrary"; TestLocationTimeZoneProvider provider = - new TestLocationTimeZoneProvider(mTestThreadingDomain, providerName); + new TestLocationTimeZoneProvider( + mTestThreadingDomain, + providerName, + mTimeZoneAvailabilityChecker); + mTimeZoneAvailabilityChecker.validIds("Europe/London"); // initialize() provider.initialize(mProviderListener); @@ -163,7 +172,10 @@ public class LocationTimeZoneProviderTest { public void defaultHandleTestCommandImpl() { String providerName = "primary"; TestLocationTimeZoneProvider provider = - new TestLocationTimeZoneProvider(mTestThreadingDomain, providerName); + new TestLocationTimeZoneProvider( + mTestThreadingDomain, + providerName, + mTimeZoneAvailabilityChecker); TestCommand testCommand = TestCommand.createForTests("test", new Bundle()); AtomicReference<Bundle> resultReference = new AtomicReference<>(); @@ -180,8 +192,12 @@ public class LocationTimeZoneProviderTest { public void stateRecording() { String providerName = "primary"; TestLocationTimeZoneProvider provider = - new TestLocationTimeZoneProvider(mTestThreadingDomain, providerName); + new TestLocationTimeZoneProvider( + mTestThreadingDomain, + providerName, + mTimeZoneAvailabilityChecker); provider.setStateChangeRecordingEnabled(true); + mTimeZoneAvailabilityChecker.validIds("Europe/London"); // initialize() provider.initialize(mProviderListener); @@ -218,6 +234,34 @@ public class LocationTimeZoneProviderTest { provider.assertLatestRecordedState(PROVIDER_STATE_DESTROYED); } + @Test + public void considerSuggestionWithInvalidTimeZoneIdsAsUncertain() { + String providerName = "primary"; + TestLocationTimeZoneProvider provider = + new TestLocationTimeZoneProvider( + mTestThreadingDomain, + providerName, + mTimeZoneAvailabilityChecker); + provider.setStateChangeRecordingEnabled(true); + provider.initialize(mProviderListener); + + ConfigurationInternal config = USER1_CONFIG_GEO_DETECTION_ENABLED; + Duration arbitraryInitializationTimeout = Duration.ofMinutes(5); + Duration arbitraryInitializationTimeoutFuzz = Duration.ofMinutes(2); + provider.startUpdates(config, arbitraryInitializationTimeout, + arbitraryInitializationTimeoutFuzz); + + List<String> invalidTimeZoneIds = asList("Atlantic/Atlantis"); + TimeZoneProviderSuggestion invalidIdSuggestion = new TimeZoneProviderSuggestion.Builder() + .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS) + .setTimeZoneIds(invalidTimeZoneIds) + .build(); + TimeZoneProviderEvent event = + TimeZoneProviderEvent.createSuggestionEvent(invalidIdSuggestion); + provider.simulateProviderEventReceived(event); + provider.assertLatestRecordedState(PROVIDER_STATE_STARTED_UNCERTAIN); + } + /** A test stand-in for the real {@link LocationTimeZoneProviderController}'s listener. */ private static class TestProviderListener implements ProviderListener { @@ -251,8 +295,9 @@ public class LocationTimeZoneProviderTest { /** Creates the instance. */ TestLocationTimeZoneProvider(@NonNull ThreadingDomain threadingDomain, - @NonNull String providerName) { - super(threadingDomain, providerName); + @NonNull String providerName, + @NonNull TimeZoneIdValidator timeZoneIdValidator) { + super(threadingDomain, providerName, timeZoneIdValidator); } @Override @@ -308,4 +353,19 @@ public class LocationTimeZoneProviderTest { recordedStates.get(recordedStates.size() - 1).stateEnum); } } + + private static final class FakeTimeZoneIdValidator + implements LocationTimeZoneProvider.TimeZoneIdValidator { + private final Set<String> mValidTimeZoneIds = new HashSet<>(); + + @Override + public boolean isValid(@NonNull String timeZoneId) { + return mValidTimeZoneIds.contains(timeZoneId); + } + + public void validIds(String... timeZoneIdss) { + mValidTimeZoneIds.addAll(asList(timeZoneIdss)); + } + + } } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java index 8280cdcb18c4..16ac1d602de5 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java @@ -44,7 +44,7 @@ final class TestSupport { @UserIdInt int userId, boolean geoDetectionEnabled) { return new ConfigurationInternal.Builder(userId) .setUserConfigAllowed(true) - .setAutoDetectionFeatureSupported(true) + .setTelephonyDetectionFeatureSupported(true) .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(true) .setLocationEnabled(true) diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidatorTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidatorTest.java new file mode 100644 index 000000000000..5561b2c6a7aa --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidatorTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.timezonedetector.location; + +import static com.google.common.truth.Truth.assertWithMessage; + +import android.platform.test.annotations.Presubmit; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.TimeZone; + +@Presubmit +public class ZoneInfoDbTimeZoneIdValidatorTest { + private final LocationTimeZoneProvider.TimeZoneIdValidator mTzChecker = + new ZoneInfoDbTimeZoneIdValidator(); + + @Test + public void timeZoneIdsFromZoneInfoDbAreValid() { + for (String timeZone : TimeZone.getAvailableIDs()) { + assertWithMessage("Time zone %s should be supported", timeZone) + .that(mTzChecker.isValid(timeZone)).isTrue(); + } + } + + @Test + public void nonExistingZones_areNotSupported() { + List<String> nonExistingTimeZones = Arrays.asList( + "SystemV/HST10", "Atlantic/Atlantis", "EUROPE/LONDON", "Etc/GMT-5:30" + ); + + for (String timeZone : nonExistingTimeZones) { + assertWithMessage(timeZone + " is not a valid time zone") + .that(mTzChecker.isValid(timeZone)) + .isFalse(); + } + } +} diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/OWNERS b/services/tests/servicestests/test-apps/SimpleServiceTestApp/OWNERS new file mode 100644 index 000000000000..72c0a9e6e90c --- /dev/null +++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/am/OWNERS diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java index 5182b3b69655..b921838e0bfc 100644 --- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java +++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java @@ -243,10 +243,18 @@ public class ShortcutManagerTestUtils { final UserHandle user = getParentUser(context); List<String> roleHolders = callWithShellPermissionIdentity( () -> roleManager.getRoleHoldersAsUser(RoleManager.ROLE_HOME, user)); - if (roleHolders.size() == 1) { + int size = roleHolders.size(); + if (size == 1) { return roleHolders.get(0); } - fail("Failed to get the default launcher for user " + context.getUserId()); + + if (size > 1) { + fail("Too many launchers for user " + user.getIdentifier() + " using role " + + RoleManager.ROLE_HOME + ": " + roleHolders); + } else { + fail("No default launcher for user " + user.getIdentifier() + " using role " + + RoleManager.ROLE_HOME); + } return null; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index d8e7582633de..c19f3489898d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -159,6 +159,11 @@ public class ActivityRecordTests extends WindowTestsBase { setBooted(mAtm); } + private TestStartingWindowOrganizer registerTestStartingWindowOrganizer() { + return new TestStartingWindowOrganizer(mAtm, + mSystemServicesTestRule.getPowerManagerWrapper()); + } + @Test public void testStackCleanupOnClearingTask() { final ActivityRecord activity = createActivityWith2LevelTask(); @@ -2294,6 +2299,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testCreateRemoveStartingWindow() { + registerTestStartingWindowOrganizer(); final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); activity.addStartingWindow(mPackageName, android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, @@ -2307,6 +2313,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testAddRemoveRace() { + registerTestStartingWindowOrganizer(); // There was once a race condition between adding and removing starting windows final ActivityRecord appToken = new ActivityBuilder(mAtm).setCreateTask(true).build(); for (int i = 0; i < 1000; i++) { @@ -2321,6 +2328,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testTransferStartingWindow() { + registerTestStartingWindowOrganizer(); final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); activity1.addStartingWindow(mPackageName, @@ -2337,9 +2345,10 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testTransferStartingWindowWhileCreating() { + final TestStartingWindowOrganizer organizer = registerTestStartingWindowOrganizer(); final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); - ((TestWindowManagerPolicy) activity1.mWmService.mPolicy).setRunnableWhenAddingSplashScreen( + organizer.setRunnableWhenAddingSplashScreen( () -> { // Surprise, ...! Transfer window in the middle of the creation flow. activity2.addStartingWindow(mPackageName, @@ -2357,6 +2366,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testTransferStartingWindowCanAnimate() { + registerTestStartingWindowOrganizer(); final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); activity1.addStartingWindow(mPackageName, @@ -2380,6 +2390,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testTransferStartingWindowFromFinishingActivity() { + registerTestStartingWindowOrganizer(); final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); final Task task = activity.getTask(); activity.addStartingWindow(mPackageName, android.R.style.Theme, null /* compatInfo */, @@ -2423,6 +2434,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testTransferStartingWindowSetFixedRotation() { + registerTestStartingWindowOrganizer(); final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); final Task task = activity.getTask(); final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build(); @@ -2454,6 +2466,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testTryTransferStartingWindowFromHiddenAboveToken() { + registerTestStartingWindowOrganizer(); // Add two tasks on top of each other. final ActivityRecord activityTop = new ActivityBuilder(mAtm).setCreateTask(true).build(); final ActivityRecord activityBottom = new ActivityBuilder(mAtm).build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index 8703c3103607..7f9e7da99579 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -154,7 +154,7 @@ public class DragDropControllerTests extends WindowTestsBase { mWindow = createDropTargetWindow("Drag test window", 0); doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0); when(mWm.mInputManager.transferTouchFocus(any(InputChannel.class), - any(InputChannel.class))).thenReturn(true); + any(InputChannel.class), any(boolean.class))).thenReturn(true); mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow); } @@ -370,7 +370,7 @@ public class DragDropControllerTests extends WindowTestsBase { .build(); assertTrue(mWm.mInputManager.transferTouchFocus(new InputChannel(), - new InputChannel())); + new InputChannel(), true /* isDragDrop */)); mToken = mTarget.performDrag(0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0, data); assertNotNull(mToken); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index 983063125ce9..c483ae9fa4c5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -141,7 +141,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { assertNull(mProvider.getControlTarget()); // We can have the control and the control target after seamless rotation. - mProvider.finishSeamlessRotation(false /* timeout */); + mProvider.finishSeamlessRotation(); mProvider.updateControlForTarget(target, false /* force */); assertNotNull(mProvider.getControl(target)); assertNotNull(mProvider.getControlTarget()); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index c6be987802b5..7a4ad7410163 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -16,6 +16,9 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; @@ -49,6 +52,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -511,6 +515,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { final WindowToken navToken = mDefaultDisplay.getDisplayPolicy().getNavigationBar().mToken; final SurfaceControl.Transaction transaction = navToken.getPendingTransaction(); + verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled( + mDefaultDisplay.mDisplayId, false); verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl()); final WindowContainer parent = navToken.getParent(); @@ -518,6 +524,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController(); mController.cleanupAnimation(REORDER_MOVE_TO_TOP); + verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled( + mDefaultDisplay.mDisplayId, true); verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl()); verify(navBarFadeAnimationController).fadeWindowToken(true); } @@ -532,6 +540,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { final WindowToken navToken = mDefaultDisplay.getDisplayPolicy().getNavigationBar().mToken; final SurfaceControl.Transaction transaction = navToken.getPendingTransaction(); + verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled( + mDefaultDisplay.mDisplayId, false); verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl()); final WindowContainer parent = navToken.getParent(); @@ -539,6 +549,51 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController(); mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled( + mDefaultDisplay.mDisplayId, true); + verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl()); + verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean()); + } + + @Test + public void testNotAttachNavigationBar_controlledByFixedRotationAnimation() { + setupForShouldAttachNavBarDuringTransition(); + FixedRotationAnimationController mockController = + mock(FixedRotationAnimationController.class); + doReturn(mockController).when(mDefaultDisplay).getFixedRotationAnimationController(); + final ActivityRecord homeActivity = createHomeActivity(); + initializeRecentsAnimationController(mController, homeActivity); + assertFalse(mController.isNavigationBarAttachedToApp()); + } + + @Test + public void testAttachNavBarInSplitScreenMode() { + setupForShouldAttachNavBarDuringTransition(); + final ActivityRecord primary = createActivityRecordWithParentTask(mDefaultDisplay, + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD); + final ActivityRecord secondary = createActivityRecordWithParentTask(mDefaultDisplay, + WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD); + final ActivityRecord homeActivity = createHomeActivity(); + homeActivity.setVisibility(true); + initializeRecentsAnimationController(mController, homeActivity); + + WindowState navWindow = mController.getNavigationBarWindow(); + final WindowToken navToken = navWindow.mToken; + final SurfaceControl.Transaction transaction = navToken.getPendingTransaction(); + + verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled( + mDefaultDisplay.mDisplayId, false); + verify(navWindow).setSurfaceTranslationY(-secondary.getBounds().top); + verify(transaction).reparent(navToken.getSurfaceControl(), secondary.getSurfaceControl()); + reset(navWindow); + + mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + final WindowContainer parent = navToken.getParent(); + final NavBarFadeAnimationController navBarFadeAnimationController = + mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController(); + verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled( + mDefaultDisplay.mDisplayId, true); + verify(navWindow).setSurfaceTranslationY(0); verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl()); verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean()); } @@ -600,9 +655,10 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { private void setupForShouldAttachNavBarDuringTransition() { mController.mShouldAttachNavBarToAppDuringTransition = true; - final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar"); + final WindowState navBar = spy(createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar")); mDefaultDisplay.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs); mWm.setRecentsAnimationController(mController); + doReturn(navBar).when(mController).getNavigationBarWindow(); final NavBarFadeAnimationController mockNavBarFadeAnimationController = mock(NavBarFadeAnimationController.class); final DisplayPolicy displayPolicy = spy(mDefaultDisplay.getDisplayPolicy()); 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 2fdd63ed93d5..c98e013479f4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -36,6 +36,8 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMAT import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -208,18 +210,20 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { } @Test - public void testZeroAnimations() { + public void testZeroAnimations() throws Exception { mController.goodToGo(TRANSIT_OLD_NONE); - verifyNoMoreInteractionsExceptAsBinder(mMockRunner); + verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any()); + verify(mMockRunner).onAnimationCancelled(); } @Test - public void testNotReallyStarted() { + public void testNotReallyStarted() throws Exception { final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin"); mController.createRemoteAnimationRecord(win.mActivityRecord, new Point(50, 100), null, new Rect(50, 100, 150, 150), null); mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN); - verifyNoMoreInteractionsExceptAsBinder(mMockRunner); + verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any()); + verify(mMockRunner).onAnimationCancelled(); } @Test @@ -250,7 +254,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { } @Test - public void testRemovedBeforeStarted() { + public void testRemovedBeforeStarted() throws Exception { final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin"); final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord, new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter; @@ -258,7 +262,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { mFinishedCallback); win.mActivityRecord.removeImmediately(); mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN); - verifyNoMoreInteractionsExceptAsBinder(mMockRunner); + verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any()); + verify(mMockRunner).onAnimationCancelled(); verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), eq(adapter)); } diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 2f1d7eb404ad..36cf9c9fb0cf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -40,6 +40,8 @@ import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.Task.ActivityState.STOPPED; import static com.android.server.wm.WindowContainer.POSITION_TOP; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -117,18 +119,19 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testKeepBoundsWhenChangingFromFreeformToFullscreen() { removeGlobalMinSizeRestriction(); - // create freeform display and a freeform app + // Create landscape freeform display and a freeform app. DisplayContent display = new TestDisplayContent.Builder(mAtm, 2000, 1000) .setCanRotate(false) .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM).build(); setUpApp(display); - // Put app window into freeform and then make it a compat app. + // Put app window into portrait freeform and then make it a compat app. final Rect bounds = new Rect(100, 100, 400, 600); mTask.setBounds(bounds); - prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); assertEquals(bounds, mActivity.getBounds()); + // Activity is not yet in size compat mode; it is filling the freeform window. + assertMaxBoundsInheritDisplayAreaBounds(); // The activity should be able to accept negative x position [-150, 100 - 150, 600]. final int dx = bounds.left + bounds.width() / 2; @@ -137,7 +140,7 @@ public class SizeCompatTests extends WindowTestsBase { final int density = mActivity.getConfiguration().densityDpi; - // change display configuration to fullscreen + // Change display configuration to fullscreen. Configuration c = new Configuration(display.getRequestedOverrideConfiguration()); c.windowConfiguration.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN); display.onRequestedOverrideConfigurationChanged(c); @@ -147,6 +150,8 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(bounds.width(), mActivity.getBounds().width()); assertEquals(bounds.height(), mActivity.getBounds().height()); assertEquals(density, mActivity.getConfiguration().densityDpi); + // Size compat mode is sandboxed at the activity level. + assertActivityMaxBoundsSandboxed(); } @Test @@ -172,6 +177,12 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(appBounds.height(), appBounds.width() * aspectRatio, 0.5f /* delta */); // The decor height should be a part of the effective bounds. assertEquals(mActivity.getBounds().height(), appBounds.height() + notchHeight); + // Activity max bounds should be sandboxed; activity is letterboxed due to aspect ratio. + assertActivityMaxBoundsSandboxed(); + // Activity max bounds ignore notch, since an app can be shown past the notch (although app + // is currently limited by the notch). + assertThat(mActivity.getWindowConfiguration().getMaxBounds().height()) + .isEqualTo(displayBounds.height()); mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); assertFitted(); @@ -181,9 +192,17 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(appBounds.width(), appBounds.height() * aspectRatio, 0.5f /* delta */); // The notch is no longer on top. assertEquals(appBounds, mActivity.getBounds()); + // Activity max bounds are sandboxed. + assertActivityMaxBoundsSandboxed(); mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); assertFitted(); + // Activity max bounds should be sandboxed; activity is letterboxed due to aspect ratio. + assertActivityMaxBoundsSandboxed(); + // Activity max bounds ignore notch, since an app can be shown past the notch (although app + // is currently limited by the notch). + assertThat(mActivity.getWindowConfiguration().getMaxBounds().height()) + .isEqualTo(displayBounds.height()); } @Test @@ -206,6 +225,9 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(originalBounds.width(), mActivity.getBounds().width()); assertEquals(originalBounds.height(), mActivity.getBounds().height()); assertEquals(originalDpi, mActivity.getConfiguration().densityDpi); + // Activity is sandboxed; it is in size compat mode since it is not resizable and has a + // max aspect ratio. + assertActivityMaxBoundsSandboxed(); assertScaled(); } @@ -213,11 +235,13 @@ public class SizeCompatTests extends WindowTestsBase { public void testFixedScreenBoundsWhenDisplaySizeChanged() { setUpDisplaySizeWithApp(1000, 2500); prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); + final DisplayContent display = mActivity.mDisplayContent; assertFitted(); + // Activity inherits bounds from TaskDisplayArea, since not sandboxed. + assertMaxBoundsInheritDisplayAreaBounds(); final Rect origBounds = new Rect(mActivity.getBounds()); final Rect currentBounds = mActivity.getWindowConfiguration().getBounds(); - final DisplayContent display = mActivity.mDisplayContent; // Change the size of current display. resizeDisplay(display, 1000, 2000); @@ -234,6 +258,8 @@ public class SizeCompatTests extends WindowTestsBase { // The position of configuration bounds should be the same as compat bounds. assertEquals(mActivity.getBounds().left, currentBounds.left); assertEquals(mActivity.getBounds().top, currentBounds.top); + // Activity is sandboxed to the offset size compat bounds. + assertActivityMaxBoundsSandboxed(); // Change display size to a different orientation resizeDisplay(display, 2000, 1000); @@ -242,6 +268,8 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(origBounds.height(), currentBounds.height()); assertEquals(ORIENTATION_LANDSCAPE, display.getConfiguration().orientation); assertEquals(Configuration.ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation); + // Activity is sandboxed to the offset size compat bounds. + assertActivityMaxBoundsSandboxed(); // The previous resize operation doesn't consider the rotation change after size changed. // These setups apply the requested orientation to rotation as real case that the top fixed @@ -261,6 +289,8 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(origBounds.height(), currentBounds.height()); assertEquals(offsetX, currentBounds.left); assertScaled(); + // Activity is sandboxed due to size compat mode. + assertActivityMaxBoundsSandboxed(); } @Test @@ -276,6 +306,8 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(bounds.width(), bounds.height() * maxAspect, 0.0001f /* delta */); // The position should be horizontal centered. assertEquals((displayWidth - bounds.width()) / 2, bounds.left); + // Activity max bounds should be sandboxed since it is letterboxed. + assertActivityMaxBoundsSandboxed(); mActivity.mDisplayContent.setImeLayeringTarget(addWindowToActivity(mActivity)); // Make sure IME cannot attach to the app, otherwise IME window will also be shifted. @@ -287,6 +319,8 @@ public class SizeCompatTests extends WindowTestsBase { // It should keep non-attachable because the resolved bounds will be computed according to // the aspect ratio that won't match its parent bounds. assertFalse(mActivity.mDisplayContent.isImeAttachedToApp()); + // Activity max bounds should be sandboxed since it is letterboxed. + assertActivityMaxBoundsSandboxed(); } @Test @@ -312,14 +346,13 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - public void testMoveToDifferentOrientDisplay() { + public void testMoveToDifferentOrientationDisplay() { setUpDisplaySizeWithApp(1000, 2500); prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); assertFitted(); - final Rect configBounds = mActivity.getWindowConfiguration().getBounds(); - final int origWidth = configBounds.width(); - final int origHeight = configBounds.height(); + final Rect currentBounds = mActivity.getWindowConfiguration().getBounds(); + final Rect originalBounds = new Rect(mActivity.getWindowConfiguration().getBounds()); final int notchHeight = 100; final DisplayContent newDisplay = new TestDisplayContent.Builder(mAtm, 2000, 1000) @@ -328,37 +361,45 @@ public class SizeCompatTests extends WindowTestsBase { // Move the non-resizable activity to the new display. mTask.reparent(newDisplay.getDefaultTaskDisplayArea(), true /* onTop */); // The configuration bounds [820, 0 - 1820, 2500] should keep the same. - assertEquals(origWidth, configBounds.width()); - assertEquals(origHeight, configBounds.height()); + assertEquals(originalBounds.width(), currentBounds.width()); + assertEquals(originalBounds.height(), currentBounds.height()); assertScaled(); + // Activity max bounds are sandboxed due to size compat mode on the new display. + assertActivityMaxBoundsSandboxed(); final Rect newDisplayBounds = newDisplay.getWindowConfiguration().getBounds(); // The scaled bounds should exclude notch area (1000 - 100 == 360 * 2500 / 1000 = 900). assertEquals(newDisplayBounds.height() - notchHeight, - (int) ((float) mActivity.getBounds().width() * origHeight / origWidth)); + (int) ((float) mActivity.getBounds().width() * originalBounds.height() + / originalBounds.width())); // Recompute the natural configuration in the new display. mActivity.clearSizeCompatMode(); mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); // Because the display cannot rotate, the portrait activity will fit the short side of // display with keeping portrait bounds [200, 0 - 700, 1000] in center. - assertEquals(newDisplayBounds.height(), configBounds.height()); - assertEquals(configBounds.height() * newDisplayBounds.height() / newDisplayBounds.width(), - configBounds.width()); + assertEquals(newDisplayBounds.height(), currentBounds.height()); + assertEquals(currentBounds.height() * newDisplayBounds.height() / newDisplayBounds.width(), + currentBounds.width()); assertFitted(); // The appBounds should be [200, 100 - 700, 1000]. final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds(); - assertEquals(configBounds.width(), appBounds.width()); - assertEquals(configBounds.height() - notchHeight, appBounds.height()); + assertEquals(currentBounds.width(), appBounds.width()); + assertEquals(currentBounds.height() - notchHeight, appBounds.height()); + // Activity max bounds are sandboxed due to letterboxing from orientation mismatch with + // display. + assertActivityMaxBoundsSandboxed(); } @Test - public void testFixedOrientRotateCutoutDisplay() { + public void testFixedOrientationRotateCutoutDisplay() { // Create a display with a notch/cutout final int notchHeight = 60; - setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2500) + final int width = 1000; + setUpApp(new TestDisplayContent.Builder(mAtm, width, 2500) .setNotch(notchHeight).build()); - // Bounds=[0, 0 - 1000, 1460], AppBounds=[0, 60 - 1000, 1460]. + // Bounds=[0, 0 - 1000, 1400], AppBounds=[0, 60 - 1000, 1460]. + final float maxAspect = 1.4f; prepareUnresizable(mActivity, 1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); final Rect currentBounds = mActivity.getWindowConfiguration().getBounds(); @@ -366,6 +407,11 @@ public class SizeCompatTests extends WindowTestsBase { final Rect origBounds = new Rect(currentBounds); final Rect origAppBounds = new Rect(appBounds); + // Activity is sandboxed, and bounds include the area consumed by the notch. + assertActivityMaxBoundsSandboxed(); + assertThat(mActivity.getConfiguration().windowConfiguration.getMaxBounds().height()) + .isEqualTo(Math.round(width * maxAspect) + notchHeight); + // Although the activity is fixed orientation, force rotate the display. rotateDisplay(mActivity.mDisplayContent, ROTATION_270); assertEquals(ROTATION_270, mTask.getWindowConfiguration().getRotation()); @@ -381,10 +427,13 @@ public class SizeCompatTests extends WindowTestsBase { // The position in configuration should be global coordinates. assertEquals(mActivity.getBounds().left, currentBounds.left); assertEquals(mActivity.getBounds().top, currentBounds.top); + + // Activity max bounds are sandboxed due to size compat mode. + assertActivityMaxBoundsSandboxed(); } @Test - public void testFixedAspOrientChangeOrient() { + public void testFixedAspectRatioOrientationChangeOrientation() { setUpDisplaySizeWithApp(1000, 2500); final float maxAspect = 1.4f; @@ -396,6 +445,8 @@ public class SizeCompatTests extends WindowTestsBase { final Rect originalAppBounds = new Rect(mActivity.getWindowConfiguration().getAppBounds()); assertEquals((int) (originalBounds.width() * maxAspect), originalBounds.height()); + // Activity is sandboxed due to fixed aspect ratio. + assertActivityMaxBoundsSandboxed(); // Change the fixed orientation. mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); @@ -407,6 +458,8 @@ public class SizeCompatTests extends WindowTestsBase { mActivity.getWindowConfiguration().getAppBounds().height()); assertEquals(originalAppBounds.height(), mActivity.getWindowConfiguration().getAppBounds().width()); + // Activity is sandboxed due to fixed aspect ratio. + assertActivityMaxBoundsSandboxed(); } @Test @@ -455,6 +508,8 @@ public class SizeCompatTests extends WindowTestsBase { // restarted and the override configuration won't be cleared. verify(mActivity, never()).restartProcessIfVisible(); assertScaled(); + // Activity max bounds are sandboxed due to size compat mode, even if is not visible. + assertActivityMaxBoundsSandboxed(); // Change display density display.mBaseDisplayDensity = (int) (0.7f * display.mBaseDisplayDensity); @@ -550,13 +605,13 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - public void testShouldUseSizeCompatModeOnResizableTask() { + public void testShouldCreateCompatDisplayInsetsOnResizeableTask() { setUpDisplaySizeWithApp(1000, 2500); // Make the task root resizable. mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; - // Create a size compat activity on the same task. + // Create an activity on the same task. final ActivityRecord activity = new ActivityBuilder(mAtm) .setTask(mTask) .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) @@ -568,26 +623,112 @@ public class SizeCompatTests extends WindowTestsBase { // in multi-window mode. mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM); assertFalse(activity.shouldCreateCompatDisplayInsets()); + // Activity should not be sandboxed. + assertMaxBoundsInheritDisplayAreaBounds(); // The non-resizable activity should not be size compat because the display support // changing windowing mode from fullscreen to freeform. mTask.mDisplayContent.setDisplayWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM); mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN); assertFalse(activity.shouldCreateCompatDisplayInsets()); + // Activity should not be sandboxed. + assertMaxBoundsInheritDisplayAreaBounds(); + } + + @Test + public void testShouldCreateCompatDisplayInsetsWhenUnresizeableAndSupportsSizeChangesTrue() { + setUpDisplaySizeWithApp(1000, 2500); + + // Make the task root resizable. + mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; + + // Create an activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) + .setSupportsSizeChanges(true) + .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + assertFalse(activity.shouldCreateCompatDisplayInsets()); + } + + @Test + public void testShouldCreateCompatDisplayInsetsWhenUnresizeableAndSupportsSizeChangesFalse() { + setUpDisplaySizeWithApp(1000, 2500); + + // Make the task root resizable. + mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; + + // Create an activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) + .setSupportsSizeChanges(false) + .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + assertTrue(activity.shouldCreateCompatDisplayInsets()); + } + + @Test + public void testShouldCreateCompatDisplayInsetsWhenResizeableAndSupportsSizeChangesFalse() { + setUpDisplaySizeWithApp(1000, 2500); + + // Make the task root resizable. + mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; + + // Create an activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setResizeMode(ActivityInfo.RESIZE_MODE_RESIZEABLE) + .setSupportsSizeChanges(false) + .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + assertFalse(activity.shouldCreateCompatDisplayInsets()); + } + + @Test + public void + testShouldCreateCompatDisplayInsetsWhenUnfixedOrientationSupportsSizeChangesFalse() { + setUpDisplaySizeWithApp(1000, 2500); + + // Make the task root resizable. + mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; + + // Create an activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) + .setSupportsSizeChanges(false) + .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + assertFalse(activity.shouldCreateCompatDisplayInsets()); } @Test @EnableCompatChanges({ActivityInfo.FORCE_RESIZE_APP}) - public void testNoSizeCompatWhenPerAppOverrideSet() { + public void testShouldCreateCompatDisplayInsetsWhenForceResizeAppOverrideSet() { setUpDisplaySizeWithApp(1000, 2500); // Make the task root resizable. mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; - // Create a size compat activity on the same task. + // Create an activity on the same task. final ActivityRecord activity = new ActivityBuilder(mAtm) .setTask(mTask) .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) + .setSupportsSizeChanges(false) .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) .setComponent(ComponentName.createRelative(mContext, SizeCompatTests.class.getName())) @@ -597,6 +738,48 @@ public class SizeCompatTests extends WindowTestsBase { } @Test + @EnableCompatChanges({ActivityInfo.FORCE_NON_RESIZE_APP}) + public void testShouldCreateCompatDisplayInsetsWhenForceNonResizeOverrideSet() { + setUpDisplaySizeWithApp(1000, 2500); + + // Make the task root resizable. + mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; + + // Create an activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setResizeMode(ActivityInfo.RESIZE_MODE_RESIZEABLE) + .setSupportsSizeChanges(true) + .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + assertTrue(activity.shouldCreateCompatDisplayInsets()); + } + + @Test + @EnableCompatChanges({ActivityInfo.FORCE_NON_RESIZE_APP}) + public void testShouldCreateCompatDisplayInsetsWhenForceNonResizeSetAndUnfixedOrientation() { + setUpDisplaySizeWithApp(1000, 2500); + + // Make the task root resizable. + mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; + + // Create an activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setResizeMode(ActivityInfo.RESIZE_MODE_RESIZEABLE) + .setSupportsSizeChanges(true) + .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + assertTrue(activity.shouldCreateCompatDisplayInsets()); + } + + @Test public void testLaunchWithFixedRotationTransform() { final int dw = 1000; final int dh = 2500; @@ -637,6 +820,9 @@ public class SizeCompatTests extends WindowTestsBase { // be transparent. assertFalse(displayPolicy.isFullyTransparentAllowed(w, TYPE_STATUS_BAR)); + // Activity is sandboxed. + assertActivityMaxBoundsSandboxed(); + // Make the activity fill the display. prepareUnresizable(mActivity, 10 /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE); w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; @@ -646,6 +832,7 @@ public class SizeCompatTests extends WindowTestsBase { // The letterbox should only cover the notch area, so status bar can be transparent. assertEquals(new Rect(notchHeight, 0, 0, 0), mActivity.getLetterboxInsets()); assertTrue(displayPolicy.isFullyTransparentAllowed(w, TYPE_STATUS_BAR)); + assertActivityMaxBoundsSandboxed(); } @Test @@ -668,6 +855,7 @@ public class SizeCompatTests extends WindowTestsBase { // App should launch in fixed orientation letterbox. assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertFalse(mActivity.inSizeCompatMode()); + assertActivityMaxBoundsSandboxed(); // Activity bounds should be 700x1400 with the ratio as the display. assertEquals(displayBounds.height(), activityBounds.height()); @@ -789,6 +977,7 @@ public class SizeCompatTests extends WindowTestsBase { assertScaled(); assertEquals(activityBounds.width(), newActivityBounds.width()); assertEquals(activityBounds.height(), newActivityBounds.height()); + assertActivityMaxBoundsSandboxed(); } @Test @@ -800,29 +989,29 @@ public class SizeCompatTests extends WindowTestsBase { // Portrait fixed app without max aspect. prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); - Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); - Rect activityBounds = new Rect(mActivity.getBounds()); - // App should launch in fullscreen. assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertFalse(mActivity.inSizeCompatMode()); - assertEquals(displayBounds, activityBounds); + // Activity inherits max bounds from TaskDisplayArea. + assertMaxBoundsInheritDisplayAreaBounds(); // Rotate display to landscape. rotateDisplay(mActivity.mDisplayContent, ROTATION_90); - displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); - activityBounds = new Rect(mActivity.getBounds()); - assertTrue(displayBounds.width() > displayBounds.height()); + final Rect rotatedDisplayBounds = new Rect(mActivity.mDisplayContent.getBounds()); + final Rect rotatedActivityBounds = new Rect(mActivity.getBounds()); + assertTrue(rotatedDisplayBounds.width() > rotatedDisplayBounds.height()); // App should be in size compat. assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertScaled(); + assertThat(mActivity.inSizeCompatMode()).isTrue(); + assertActivityMaxBoundsSandboxed(); // App bounds should be 700x1400 with the ratio as the display. - assertEquals(displayBounds.height(), activityBounds.height()); - assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(), - activityBounds.width()); + assertEquals(rotatedDisplayBounds.height(), rotatedActivityBounds.height()); + assertEquals(rotatedDisplayBounds.height() * rotatedDisplayBounds.height() + / rotatedDisplayBounds.width(), rotatedActivityBounds.width()); } @Test @@ -859,6 +1048,7 @@ public class SizeCompatTests extends WindowTestsBase { // has 700x1400 bounds with the ratio as the display. assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertFalse(newActivity.inSizeCompatMode()); + assertActivityMaxBoundsSandboxed(); assertEquals(taskBounds, displayBounds); assertEquals(displayBounds.height(), newActivityBounds.height()); assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(), @@ -899,6 +1089,11 @@ public class SizeCompatTests extends WindowTestsBase { // Task bounds should fill parent bounds. assertEquals(displayBounds, taskBounds); + // Prior and new activity max bounds are sandboxed due to letterbox. + assertThat(newActivity.getConfiguration().windowConfiguration.getMaxBounds()) + .isEqualTo(newActivityBounds); + assertActivityMaxBoundsSandboxed(); + // Activity bounds should be (1400 / 1.3 = 1076)x1400 with the app requested ratio. assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertFalse(newActivity.inSizeCompatMode()); @@ -927,6 +1122,9 @@ public class SizeCompatTests extends WindowTestsBase { // App should be in size compat. assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertScaled(); + assertThat(mActivity.inSizeCompatMode()).isTrue(); + // Activity max bounds are sandboxed due to size compat mode. + assertActivityMaxBoundsSandboxed(); final Rect activityBounds = new Rect(mActivity.getBounds()); mTask.resumeTopActivityUncheckedLocked(null /* prev */, null /* options */); @@ -936,6 +1134,8 @@ public class SizeCompatTests extends WindowTestsBase { assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertScaled(); assertEquals(activityBounds, mActivity.getBounds()); + // Activity max bounds are sandboxed due to size compat. + assertActivityMaxBoundsSandboxed(); } @Test @@ -951,6 +1151,7 @@ public class SizeCompatTests extends WindowTestsBase { // In fixed orientation letterbox assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertFalse(mActivity.inSizeCompatMode()); + assertActivityMaxBoundsSandboxed(); // Rotate display to portrait. rotateDisplay(display, ROTATION_90); @@ -958,13 +1159,15 @@ public class SizeCompatTests extends WindowTestsBase { // App should be in size compat. assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertScaled(); + assertActivityMaxBoundsSandboxed(); // Rotate display to landscape. rotateDisplay(display, ROTATION_180); - // In Task letterbox + // In activity letterbox assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertFalse(mActivity.inSizeCompatMode()); + assertActivityMaxBoundsSandboxed(); } @Test @@ -982,20 +1185,23 @@ public class SizeCompatTests extends WindowTestsBase { // In fixed orientation letterbox assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertFalse(mActivity.inSizeCompatMode()); + assertActivityMaxBoundsSandboxed(); - // Rotate display to portrait. + // Rotate display to landscape. rotateDisplay(display, ROTATION_90); // App should be in size compat. assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertScaled(); + assertActivityMaxBoundsSandboxed(); - // Rotate display to landscape. + // Rotate display to portrait. rotateDisplay(display, ROTATION_180); // In fixed orientation letterbox assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); assertFalse(mActivity.inSizeCompatMode()); + assertActivityMaxBoundsSandboxed(); } @Test @@ -1012,12 +1218,18 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(ORIENTATION_LANDSCAPE, display.getConfiguration().orientation); assertEquals(2800, displayBounds.width()); assertEquals(1400, displayBounds.height()); - taskDisplayArea.setBounds(0, 0, 2400, 1000); + Rect displayAreaBounds = new Rect(0, 0, 2400, 1000); + taskDisplayArea.setBounds(displayAreaBounds); final Rect activityBounds = new Rect(mActivity.getBounds()); assertFalse(mActivity.inSizeCompatMode()); assertEquals(2400, activityBounds.width()); assertEquals(1000, activityBounds.height()); + // Task and activity maximum bounds inherit from TaskDisplayArea bounds. + assertThat(mActivity.getConfiguration().windowConfiguration.getMaxBounds()) + .isEqualTo(displayAreaBounds); + assertThat(mTask.getConfiguration().windowConfiguration.getMaxBounds()) + .isEqualTo(displayAreaBounds); } @Test @@ -1042,6 +1254,7 @@ public class SizeCompatTests extends WindowTestsBase { assertScaled(); assertEquals(originalBounds, mActivity.getConfiguration().windowConfiguration.getBounds()); + assertActivityMaxBoundsSandboxed(); // Recompute the natural configuration of the non-resizable activity and the split screen. mActivity.clearSizeCompatMode(); @@ -1053,12 +1266,13 @@ public class SizeCompatTests extends WindowTestsBase { addWindowToActivity(mActivity); mActivity.mRootWindowContainer.performSurfacePlacement(); - // Split screen is also in portrait [1000,1400], so activty should be in fixed orientation + // Split screen is also in portrait [1000,1400], so activity should be in fixed orientation // letterbox. assertEquals(ORIENTATION_PORTRAIT, mTask.getConfiguration().orientation); assertEquals(ORIENTATION_LANDSCAPE, mActivity.getConfiguration().orientation); assertFitted(); assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); + assertActivityMaxBoundsSandboxed(); // Letterbox should fill the gap between the split screen and the letterboxed activity. final Rect primarySplitBounds = new Rect(organizer.mPrimary.getBounds()); @@ -1165,6 +1379,22 @@ public class SizeCompatTests extends WindowTestsBase { assertFalse(mActivity.hasSizeCompatBounds()); } + /** Asserts the activity max bounds inherit from the TaskDisplayArea. */ + private void assertMaxBoundsInheritDisplayAreaBounds() { + assertThat(mActivity.getConfiguration().windowConfiguration.getMaxBounds()) + .isEqualTo(mTask.getDisplayArea().getBounds()); + } + + /** + * Asserts activity-level letterbox or size compat mode size compat mode, so activity max + * bounds are sandboxed. + */ + private void assertActivityMaxBoundsSandboxed() { + // Activity max bounds are sandboxed due to size compat mode. + assertThat(mActivity.getConfiguration().windowConfiguration.getMaxBounds()) + .isEqualTo(mActivity.getWindowConfiguration().getBounds()); + } + static Configuration rotateDisplay(DisplayContent display, int rotation) { final Configuration c = new Configuration(); display.getDisplayRotation().setRotation(rotation); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java index 75226b7e66f7..8bc4cedf6fce 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java @@ -34,7 +34,6 @@ import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; import android.view.InputChannel; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; @@ -63,7 +62,8 @@ public class TaskPositioningControllerTests extends WindowTestsBase { when(mWm.mInputManager.transferTouchFocus( any(InputChannel.class), - any(InputChannel.class))).thenReturn(true); + any(InputChannel.class), + any(boolean.class))).thenReturn(true); mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window"); mWindow.getTask().setResizeMode(RESIZE_MODE_RESIZEABLE); 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 ecb8b607a106..dca6b089d66b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -26,6 +26,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG; import static com.google.common.truth.Truth.assertThat; @@ -277,4 +278,15 @@ public class TaskTests extends WindowTestsBase { // Orientation request from standard activity in multi window will not be handled. assertFalse(leafTask2.handlesOrientationChangeFromDescendant()); } + + @Test + public void testAlwaysOnTop() { + final Task task = createTaskStackOnDisplay(mDisplayContent); + task.setAlwaysOnTop(true); + task.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + assertTrue(task.isAlwaysOnTop()); + + task.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, true /* set */); + assertFalse(task.isAlwaysOnTop()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java index ae85ceb72958..cac69657f5cc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java @@ -136,6 +136,7 @@ class TestDisplayContent extends DisplayContent { final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, mInfo, DEFAULT_DISPLAY_ADJUSTMENTS); final TestDisplayContent newDisplay = createInternal(display); + // disable the normal system decorations final DisplayPolicy displayPolicy = newDisplay.getDisplayPolicy(); spyOn(displayPolicy); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index 86d8eee878fd..7822a8514a13 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -119,7 +119,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { mRunnableWhenAddingSplashScreen.run(); mRunnableWhenAddingSplashScreen = null; } - return () -> { + return (a) -> { synchronized (wm.mGlobalLock) { activity.removeChild(window); activity.mStartingWindow = null; diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 2c2c09a5750a..01c503e01326 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -547,7 +547,8 @@ public class WindowOrganizerTests extends WindowTestsBase { } @Override - public void removeStartingWindow(int taskId) { } + public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { } @Override public void copySplashScreenView(int taskId) { } @@ -614,7 +615,8 @@ public class WindowOrganizerTests extends WindowTestsBase { } @Override - public void removeStartingWindow(int taskId) { } + public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { } @Override public void copySplashScreenView(int taskId) { } @Override @@ -688,7 +690,8 @@ public class WindowOrganizerTests extends WindowTestsBase { } @Override - public void removeStartingWindow(int taskId) { } + public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { } @Override public void copySplashScreenView(int taskId) { } @Override @@ -832,7 +835,8 @@ public class WindowOrganizerTests extends WindowTestsBase { @Override public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { } @Override - public void removeStartingWindow(int taskId) { } + public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { } @Override public void copySplashScreenView(int taskId) { } @Override 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 51aec65f7285..5b5b1da327bd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -521,7 +521,7 @@ public class WindowStateTests extends WindowTestsBase { matrix.mapPoints(curSurfacePos); verify(t).setPosition(eq(app.mSurfaceControl), eq(curSurfacePos[0]), eq(curSurfacePos[1])); - app.finishSeamlessRotation(false /* timeout */); + app.finishSeamlessRotation(t); assertFalse(app.mSeamlesslyRotated); assertNull(app.mPendingSeamlessRotate); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 8d50a77447da..4a7784cf1b36 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -36,6 +36,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; @@ -50,6 +51,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wm.StartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN; @@ -67,6 +69,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.Build; import android.os.Bundle; @@ -74,6 +77,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; +import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; import android.view.IDisplayWindowInsetsController; @@ -100,6 +104,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.HashMap; /** Common base class for window manager unit test classes. */ class WindowTestsBase extends SystemServiceTestsBase { @@ -176,6 +181,11 @@ class WindowTestsBase extends SystemServiceTestsBase { } else { mDisplayContent = mDefaultDisplay; } + + // Ensure letterbox aspect ratio is not overridden on any device target. + // {@link com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}, is set + // on some device form factors. + mAtm.mWindowManager.setFixedOrientationLetterboxAspectRatio(0); } private void createTestDisplay(UseTestDisplay annotation) { @@ -704,6 +714,7 @@ class WindowTestsBase extends SystemServiceTestsBase { private int mLaunchMode; private int mResizeMode = RESIZE_MODE_RESIZEABLE; private float mMaxAspectRatio; + private boolean mSupportsSizeChanges; private int mScreenOrientation = SCREEN_ORIENTATION_UNSPECIFIED; private boolean mLaunchTaskBehind = false; private int mConfigChanges; @@ -782,6 +793,11 @@ class WindowTestsBase extends SystemServiceTestsBase { return this; } + ActivityBuilder setSupportsSizeChanges(boolean supportsSizeChanges) { + mSupportsSizeChanges = supportsSizeChanges; + return this; + } + ActivityBuilder setScreenOrientation(int screenOrientation) { mScreenOrientation = screenOrientation; return this; @@ -869,6 +885,7 @@ class WindowTestsBase extends SystemServiceTestsBase { aInfo.launchMode = mLaunchMode; aInfo.resizeMode = mResizeMode; aInfo.maxAspectRatio = mMaxAspectRatio; + aInfo.supportsSizeChanges = mSupportsSizeChanges; aInfo.screenOrientation = mScreenOrientation; aInfo.configChanges |= mConfigChanges; aInfo.taskAffinity = mAffinity; @@ -1111,6 +1128,88 @@ class WindowTestsBase extends SystemServiceTestsBase { } } + static class TestStartingWindowOrganizer extends ITaskOrganizer.Stub { + private final ActivityTaskManagerService mAtm; + private final WindowManagerService mWMService; + private final WindowState.PowerManagerWrapper mPowerManagerWrapper; + + private Runnable mRunnableWhenAddingSplashScreen; + private final SparseArray<IBinder> mTaskAppMap = new SparseArray<>(); + private final HashMap<IBinder, WindowState> mAppWindowMap = new HashMap<>(); + + TestStartingWindowOrganizer(ActivityTaskManagerService service, + WindowState.PowerManagerWrapper powerManagerWrapper) { + mAtm = service; + mWMService = mAtm.mWindowManager; + mPowerManagerWrapper = powerManagerWrapper; + if (DEBUG_ENABLE_SHELL_DRAWER) { + mAtm.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer(Runnable::run); + mAtm.mTaskOrganizerController.registerTaskOrganizer(this); + } + } + + void setRunnableWhenAddingSplashScreen(Runnable r) { + if (DEBUG_ENABLE_SHELL_DRAWER) { + mRunnableWhenAddingSplashScreen = r; + } else { + ((TestWindowManagerPolicy) mWMService.mPolicy).setRunnableWhenAddingSplashScreen(r); + } + } + + @Override + public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { + synchronized (mWMService.mGlobalLock) { + final ActivityRecord activity = mWMService.mRoot.getActivityRecord( + appToken); + IWindow iWindow = mock(IWindow.class); + doReturn(mock(IBinder.class)).when(iWindow).asBinder(); + final WindowState window = WindowTestsBase.createWindow(null, + TYPE_APPLICATION_STARTING, activity, + "Starting window", 0 /* ownerId */, 0 /* userId*/, + false /* internalWindows */, mWMService, mock(Session.class), + iWindow, + mPowerManagerWrapper); + activity.mStartingWindow = window; + mAppWindowMap.put(appToken, window); + mTaskAppMap.put(info.taskInfo.taskId, appToken); + } + if (mRunnableWhenAddingSplashScreen != null) { + mRunnableWhenAddingSplashScreen.run(); + mRunnableWhenAddingSplashScreen = null; + } + } + @Override + public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { + synchronized (mWMService.mGlobalLock) { + final IBinder appToken = mTaskAppMap.get(taskId); + if (appToken != null) { + mTaskAppMap.remove(taskId); + final ActivityRecord activity = mWMService.mRoot.getActivityRecord( + appToken); + WindowState win = mAppWindowMap.remove(appToken); + activity.removeChild(win); + activity.mStartingWindow = null; + } + } + } + @Override + public void copySplashScreenView(int taskId) { + } + @Override + public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) { + } + @Override + public void onTaskVanished(ActivityManager.RunningTaskInfo info) { + } + @Override + public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { + } + @Override + public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { + } + } + static class TestSplitOrganizer extends ITaskOrganizer.Stub { final ActivityTaskManagerService mService; Task mPrimary; @@ -1149,7 +1248,8 @@ class WindowTestsBase extends SystemServiceTestsBase { public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { } @Override - public void removeStartingWindow(int taskId) { + public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, + boolean playRevealAnimation) { } @Override public void copySplashScreenView(int taskId) { diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java index c82ba995f12e..d967891fdb76 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -470,7 +470,7 @@ public class ZOrderingTests extends WindowTestsBase { mWm, mockRunner, null, displayId); spyOn(controller); controller.mShouldAttachNavBarToAppDuringTransition = true; - doReturn(mNavBarWindow.mToken).when(controller).getNavigationBarWindowToken(); + doReturn(mNavBarWindow).when(controller).getNavigationBarWindow(); mWm.setRecentsAnimationController(controller); // set ime visible diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index ed71d17b0dde..e089995a7b1c 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -17,6 +17,7 @@ package com.android.server.voiceinteraction; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -25,8 +26,10 @@ import android.hardware.soundtrigger.SoundTrigger; import android.media.AudioAttributes; import android.media.AudioRecord; import android.media.MediaRecorder; +import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.SharedMemory; import android.service.voice.AlwaysOnHotwordDetector; import android.service.voice.HotwordDetectionService; import android.service.voice.IDspHotwordDetectionCallback; @@ -74,7 +77,8 @@ final class HotwordDetectionConnection { boolean mBound; HotwordDetectionConnection(Object lock, Context context, ComponentName serviceName, - int userId, boolean bindInstantServiceAllowed) { + int userId, boolean bindInstantServiceAllowed, @Nullable Bundle options, + @Nullable SharedMemory sharedMemory) { mLock = lock; mContext = context; mDetectionComponentName = serviceName; @@ -90,6 +94,14 @@ final class HotwordDetectionConnection { boolean connected) { synchronized (mLock) { mBound = connected; + if (connected) { + try { + service.setConfig(options, sharedMemory); + } catch (RemoteException e) { + // TODO: (b/181842909) Report an error to voice interactor + Slog.w(TAG, "Failed to setConfig for HotwordDetectionService", e); + } + } } } @@ -117,6 +129,11 @@ final class HotwordDetectionConnection { } } + void setConfigLocked(Bundle options, SharedMemory sharedMemory) { + mRemoteHotwordDetectionService.run( + service -> service.setConfig(options, sharedMemory)); + } + private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent, IHotwordRecognitionStatusCallback externalCallback) { if (DEBUG) { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index dce63ebb0889..2626bfdc3d19 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -60,6 +60,7 @@ import android.os.RemoteCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.SharedMemory; import android.os.ShellCallback; import android.os.Trace; import android.os.UserHandle; @@ -982,23 +983,46 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public int setHotwordDetectionConfig(Bundle options) { + public void setHotwordDetectionServiceConfig(@Nullable Bundle options, + @Nullable SharedMemory sharedMemory) { synchronized (this) { enforceIsCurrentVoiceInteractionService(); if (mImpl == null) { Slog.w(TAG, - "setHotwordDetectionConfig without running voice interaction service"); - return VoiceInteractionService.HOTWORD_CONFIG_FAILURE; + "setHotwordDetectionServiceConfig without running voice" + + " interaction service"); + return; + } + final long caller = Binder.clearCallingIdentity(); + try { + mImpl.setHotwordDetectionServiceConfigLocked(options, sharedMemory); + } finally { + Binder.restoreCallingIdentity(caller); + } + } + } + + @Override + public void shutdownHotwordDetectionService() { + synchronized (this) { + enforceIsCurrentVoiceInteractionService(); + + if (mImpl == null) { + Slog.w(TAG, + "shutdownHotwordDetectionService without running voice" + + " interaction service"); + return; } final long caller = Binder.clearCallingIdentity(); try { - return mImpl.setHotwordDetectionConfigLocked(options); + mImpl.shutdownHotwordDetectionServiceLocked(); } finally { Binder.restoreCallingIdentity(caller); } } } + //----------------- Model management APIs --------------------------------// @Override diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 04dea3f7a2c6..58616104755d 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -43,11 +43,13 @@ import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SharedMemory; import android.os.UserHandle; import android.service.voice.IVoiceInteractionService; import android.service.voice.IVoiceInteractionSession; import android.service.voice.VoiceInteractionService; import android.service.voice.VoiceInteractionServiceInfo; +import android.system.OsConstants; import android.util.PrintWriterPrinter; import android.util.Slog; import android.view.IWindowManager; @@ -389,25 +391,48 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return mInfo.getSupportsLocalInteraction(); } - public int setHotwordDetectionConfigLocked(Bundle options) { + public void setHotwordDetectionServiceConfigLocked(@Nullable Bundle options, + @Nullable SharedMemory sharedMemory) { if (DEBUG) { - Slog.d(TAG, "setHotwordDetectionConfigLocked"); + Slog.d(TAG, "setHotwordDetectionServiceConfigLocked"); } if (mHotwordDetectionComponentName == null) { - Slog.e(TAG, "Calling setHotwordDetectionConfigLocked, but hotword detection service" - + " name not found"); - return VoiceInteractionService.HOTWORD_CONFIG_FAILURE; + Slog.w(TAG, "Hotword detection service name not found"); + throw new IllegalStateException("Hotword detection service name not found"); } if (!isIsolatedProcessLocked(mHotwordDetectionComponentName)) { - return VoiceInteractionService.HOTWORD_CONFIG_FAILURE; + Slog.w(TAG, "Hotword detection service not in isolated process"); + throw new IllegalStateException("Hotword detection service not in isolated process"); } // TODO : Need to check related permissions for hotword detection service // TODO : Sanitize for bundle - mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext, - mHotwordDetectionComponentName, mUser, /* bindInstantServiceAllowed= */ false); + if (sharedMemory != null && !sharedMemory.setProtect(OsConstants.PROT_READ)) { + Slog.w(TAG, "Can't set sharedMemory to be read-only"); + throw new IllegalStateException("Can't set sharedMemory to be read-only"); + } + + if (mHotwordDetectionConnection == null) { + mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext, + mHotwordDetectionComponentName, mUser, /* bindInstantServiceAllowed= */ false, + options, sharedMemory); + } else { + mHotwordDetectionConnection.setConfigLocked(options, sharedMemory); + } + } + + public void shutdownHotwordDetectionServiceLocked() { + if (DEBUG) { + Slog.d(TAG, "shutdownHotwordDetectionServiceLocked"); + } + + if (mHotwordDetectionConnection == null) { + Slog.w(TAG, "shutdown, but no hotword detection connection"); + return; + } - return VoiceInteractionService.HOTWORD_CONFIG_SUCCESS; + mHotwordDetectionConnection.cancelLocked(); + mHotwordDetectionConnection = null; } public IRecognitionStatusCallback createSoundTriggerCallbackLocked( diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index dc2fb948fdbe..f84dd7b0bb17 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -338,7 +338,7 @@ public abstract class Conference extends Conferenceable { * * @param videoState The video state in which to answer the connection. */ - public void onAnswer(int videoState) {} + public void onAnswer(@VideoProfile.VideoState int videoState) {} /** * Notifies this Conference, which is in {@code STATE_RINGING}, of diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index c189b19c71af..d8bd6a576fad 100755 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.app.Service; import android.content.ComponentName; import android.content.Intent; @@ -1919,6 +1920,7 @@ public abstract class ConnectionService extends Service { /** {@inheritDoc} */ @Override public final IBinder onBind(Intent intent) { + onBindClient(intent); return mBinder; } @@ -1929,6 +1931,13 @@ public abstract class ConnectionService extends Service { return super.onUnbind(intent); } + /** + * Used for testing to let the test suite know when the connection service has been bound. + * @hide + */ + @TestApi + public void onBindClient(@Nullable Intent intent) { + } /** * This can be used by telecom to either create a new outgoing conference call or attach @@ -2585,9 +2594,9 @@ public abstract class ConnectionService extends Service { * @return The {@code Connection} object to satisfy this call, or {@code null} to * not handle the call. */ - public final RemoteConnection createRemoteIncomingConnection( - PhoneAccountHandle connectionManagerPhoneAccount, - ConnectionRequest request) { + public final @Nullable RemoteConnection createRemoteIncomingConnection( + @NonNull PhoneAccountHandle connectionManagerPhoneAccount, + @NonNull ConnectionRequest request) { return mRemoteConnectionManager.createRemoteConnection( connectionManagerPhoneAccount, request, true); } @@ -2604,9 +2613,9 @@ public abstract class ConnectionService extends Service { * @return The {@code Connection} object to satisfy this call, or {@code null} to * not handle the call. */ - public final RemoteConnection createRemoteOutgoingConnection( - PhoneAccountHandle connectionManagerPhoneAccount, - ConnectionRequest request) { + public final @Nullable RemoteConnection createRemoteOutgoingConnection( + @NonNull PhoneAccountHandle connectionManagerPhoneAccount, + @NonNull ConnectionRequest request) { return mRemoteConnectionManager.createRemoteConnection( connectionManagerPhoneAccount, request, false); } @@ -2846,12 +2855,14 @@ public abstract class ConnectionService extends Service { * @param connectionManagerPhoneAccount See description at * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. * @param request Details about the incoming conference call. - * @return The {@code Conference} object to satisfy this call, or {@code null} to - * not handle the call. + * @return The {@code Conference} object to satisfy this call. If the conference attempt is + * failed, the return value will be a result of an invocation of + * {@link Connection#createFailedConnection(DisconnectCause)}. + * Return {@code null} if the {@link ConnectionService} cannot handle the call. */ public @Nullable Conference onCreateIncomingConference( - @Nullable PhoneAccountHandle connectionManagerPhoneAccount, - @Nullable ConnectionRequest request) { + @NonNull PhoneAccountHandle connectionManagerPhoneAccount, + @NonNull ConnectionRequest request) { return null; } @@ -2954,8 +2965,8 @@ public abstract class ConnectionService extends Service { * @param request The outgoing connection request. */ public void onCreateOutgoingConferenceFailed( - @Nullable PhoneAccountHandle connectionManagerPhoneAccount, - @Nullable ConnectionRequest request) { + @NonNull PhoneAccountHandle connectionManagerPhoneAccount, + @NonNull ConnectionRequest request) { } @@ -3019,12 +3030,14 @@ public abstract class ConnectionService extends Service { * a {@code PhoneAccount} registered by this {@code ConnectionService} to use for * making the connection. * @param request Details about the outgoing call. - * @return The {@code Conference} object to satisfy this call, or the result of an invocation - * of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call. + * @return The {@code Conference} object to satisfy this call. If the conference attempt is + * failed, the return value will be a result of an invocation of + * {@link Connection#createFailedConnection(DisconnectCause)}. + * Return {@code null} if the {@link ConnectionService} cannot handle the call. */ public @Nullable Conference onCreateOutgoingConference( - @Nullable PhoneAccountHandle connectionManagerPhoneAccount, - @Nullable ConnectionRequest request) { + @NonNull PhoneAccountHandle connectionManagerPhoneAccount, + @NonNull ConnectionRequest request) { return null; } diff --git a/telephony/java/android/telephony/CarrierBandwidth.java b/telephony/java/android/telephony/CarrierBandwidth.java index b153fefce6e3..9e1dee0162b9 100644 --- a/telephony/java/android/telephony/CarrierBandwidth.java +++ b/telephony/java/android/telephony/CarrierBandwidth.java @@ -101,7 +101,7 @@ public final class CarrierBandwidth implements Parcelable { } /** - * Retrieves the upstream bandwidth for the primary network in Kbps. This always only refers to + * Retrieves the upstream bandwidth for the primary network in kbps. This always only refers to * the estimated first hop transport bandwidth. * This will be {@link #INVALID} if the network is not connected * @@ -112,7 +112,7 @@ public final class CarrierBandwidth implements Parcelable { } /** - * Retrieves the downstream bandwidth for the primary network in Kbps. This always only refers + * Retrieves the downstream bandwidth for the primary network in kbps. This always only refers * to the estimated first hop transport bandwidth. * This will be {@link #INVALID} if the network is not connected * @@ -123,7 +123,7 @@ public final class CarrierBandwidth implements Parcelable { } /** - * Retrieves the upstream bandwidth for the secondary network in Kbps. This always only refers + * Retrieves the upstream bandwidth for the secondary network in kbps. This always only refers * to the estimated first hop transport bandwidth. * <p/> * This will be {@link #INVALID} if either are the case: @@ -143,7 +143,7 @@ public final class CarrierBandwidth implements Parcelable { } /** - * Retrieves the downstream bandwidth for the secondary network in Kbps. This always only + * Retrieves the downstream bandwidth for the secondary network in kbps. This always only * refers to the estimated first hop transport bandwidth. * <p/> * This will be {@link #INVALID} if either are the case: diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index b52f49190679..1a71f808daa7 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -27,6 +27,7 @@ import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; +import android.net.ipsec.ike.SaProposal; import android.os.Build; import android.os.PersistableBundle; import android.os.RemoteException; @@ -35,7 +36,6 @@ import android.telecom.TelecomManager; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.ImsSsData; -import android.telephony.ims.SipDelegateManager; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.feature.RcsFeature; @@ -1341,6 +1341,38 @@ public class CarrierConfigManager { "support_ims_conference_event_package_on_peer_bool"; /** + * Indicates whether the carrier supports the use of RFC8285 compliant RTP header extensions for + * the purpose of device to device communication while in a call. + * <p> + * See also {@link #KEY_SUPPORTS_SDP_NEGOTIATION_OF_D2D_RTP_HEADER_EXTENSIONS_BOOL}. + */ + public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL = + "supports_device_to_device_communication_using_rtp_bool"; + + /** + * Indicates whether the carrier supports the negotiations of RFC8285 compliant RTP header + * extensions supported on a call during the Session Description Protocol (SDP). This option + * is only used when {@link #KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL} is + * {@code true}. + * <p> + * When {@code true}, the RTP header extensions the platform uses for device to device + * communication will be offered to the remote end during the SDP negotiation process. + * When {@code false}, the RTP header extensions will not be negotiated during the SDP + * negotiation process and the platform will send RTP header extensions without prior + * negotiation if {@link #KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL} is + * {@code true}. + */ + public static final String KEY_SUPPORTS_SDP_NEGOTIATION_OF_D2D_RTP_HEADER_EXTENSIONS_BOOL = + "supports_sdp_negotiation_of_d2d_rtp_header_extensions_bool"; + + /** + * Indicates whether the carrier supports the use of DTMF digits A-D for the purpose of device + * to device communication while in a call. + */ + public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL = + "supports_device_to_device_communication_using_dtmf_bool"; + + /** * Determines whether High Definition audio property is displayed in the dialer UI. * If {@code false}, remove the HD audio property from the connection so that HD audio related * UI is not displayed. If {@code true}, keep HD audio property as it is configured. @@ -1537,15 +1569,13 @@ public class CarrierConfigManager { "wfc_carrier_name_override_by_pnn_bool"; /** - * Value for {#CROSS_SIM_SPN_FORMAT_CARRIER_NAME_WITH_BRANDING} cnfig. - * specifies SPN format of displaying carrier name only. + * Specifies SPN format of displaying carrier name only. * */ public static final int CROSS_SIM_SPN_FORMAT_CARRIER_NAME_ONLY = 0; /** - * Value for {#CROSS_SIM_SPN_FORMAT_CARRIER_NAME_WITH_BRANDING} cnfig. - * specifies SPN format of displaying carrier name along with "Cross-SIM calling". + * Specifies SPN format of displaying carrier name along with "Cross-SIM calling". */ public static final int CROSS_SIM_SPN_FORMAT_CARRIER_NAME_WITH_BRANDING = 1; @@ -1554,8 +1584,8 @@ public class CarrierConfigManager { * * <p>Available options are: * <ul> - * <li> {#CROSS_SIM_SPN_FORMAT_CARRIER_NAME_ONLY}: %s</li> - * <li> {#CROSS_SIM_SPN_FORMAT_CARRIER_NAME_WITH_BRANDING}: %s Cross-SIM Calling</li> + * <li> {@link #CROSS_SIM_SPN_FORMAT_CARRIER_NAME_ONLY}: %s</li> + * <li> {@link #CROSS_SIM_SPN_FORMAT_CARRIER_NAME_WITH_BRANDING}: %s Cross-SIM Calling</li> * </ul> * %s will be filled with carrier name */ @@ -4141,9 +4171,11 @@ public class CarrierConfigManager { KEY_PREFIX + "child_sa_rekey_soft_timer_sec_int"; /** - * Supported DH groups for IKE negotiation. Possible values are {@link #DH_GROUP_NONE}, - * {@link #DH_GROUP_1024_BIT_MODP}, {@link #DH_GROUP_1536_BIT_MODP}, {@link - * #DH_GROUP_2048_BIT_MODP} + * Supported DH groups for IKE negotiation. Possible values are: + * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_NONE}, + * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_1024_BIT_MODP}, + * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_1536_BIT_MODP}, + * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_2048_BIT_MODP} */ public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY = KEY_PREFIX + "diffie_hellman_groups_int_array"; @@ -4179,23 +4211,29 @@ public class CarrierConfigManager { /** * List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of child - * session. Possible values are {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, {@link - * #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256} + * session. Possible values are: + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256} */ public static final String KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = KEY_PREFIX + "child_session_aes_cbc_key_size_int_array"; /** * List of supported key sizes for AES Counter (CTR) encryption mode of child session. - * Possible values are {@link #KEY_LEN_UNUSED}, - * {@link #KEY_LEN_AES_128}, {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256} + * Possible values are: + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256} */ public static final String KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = KEY_PREFIX + "child_session_aes_ctr_key_size_int_array"; /** * List of supported encryption algorithms for child session. Possible values are - * {@link #ENCRYPTION_ALGORITHM_AES_CBC} + * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CBC} */ public static final String KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = KEY_PREFIX + "supported_child_session_encryption_algorithms_int_array"; @@ -4216,8 +4254,11 @@ public class CarrierConfigManager { /** * List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of IKE - * session. Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, {@link - * #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256} + * session. Possible values: + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256} */ public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = KEY_PREFIX + "ike_session_encryption_aes_cbc_key_size_int_array"; @@ -4225,24 +4266,31 @@ public class CarrierConfigManager { /** * List of supported key sizes for AES Counter (CTR) encryption mode of IKE session. - * Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, - * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256} + * Possible values - + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192}, + * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256} */ public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = KEY_PREFIX + "ike_session_encryption_aes_ctr_key_size_int_array"; /** * List of supported encryption algorithms for IKE session. Possible values are - * {@link #ENCRYPTION_ALGORITHM_AES_CBC}, {@link #ENCRYPTION_ALGORITHM_AES_CTR} + * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CBC}, + * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CTR} */ public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = KEY_PREFIX + "supported_ike_session_encryption_algorithms_int_array"; /** - * List of supported integrity algorithms for IKE session Possible values are {@link - * #INTEGRITY_ALGORITHM_NONE}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA1_96}, {@link - * #INTEGRITY_ALGORITHM_AES_XCBC_96}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_256_128}, {@link - * #INTEGRITY_ALGORITHM_HMAC_SHA2_384_192}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_512_256} + * List of supported integrity algorithms for IKE session. Possible values are + * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_NONE}, + * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA1_96}, + * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_AES_XCBC_96}, + * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_256_128}, + * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_384_192}, + * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_512_256} */ public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY = KEY_PREFIX + "supported_integrity_algorithms_int_array"; @@ -4262,9 +4310,11 @@ public class CarrierConfigManager { /** * List of supported pseudo random function algorithms for IKE session. Possible values are - * {@link #PSEUDORANDOM_FUNCTION_HMAC_SHA1}, {@link #PSEUDORANDOM_FUNCTION_AES128_XCBC}, - * {@link #PSEUDORANDOM_FUNCTION_SHA2_256}, {@link #PSEUDORANDOM_FUNCTION_SHA2_384}, - * {@link #PSEUDORANDOM_FUNCTION_SHA2_512} + * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_HMAC_SHA1}, + * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_AES128_XCBC}, + * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_256}, + * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_384}, + * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_512} */ public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY = KEY_PREFIX + "supported_prf_algorithms_int_array"; @@ -4337,182 +4387,6 @@ public class CarrierConfigManager { public static final int EPDG_ADDRESS_CELLULAR_LOC = 3; /** @hide */ - @IntDef({KEY_LEN_UNUSED, KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256}) - public @interface EncrpytionKeyLengthType {} - - public static final int KEY_LEN_UNUSED = 0; - /** AES Encryption/Ciphering Algorithm key length 128 bits. */ - public static final int KEY_LEN_AES_128 = 128; - /** AES Encryption/Ciphering Algorithm key length 192 bits. */ - public static final int KEY_LEN_AES_192 = 192; - /** AES Encryption/Ciphering Algorithm key length 256 bits. */ - public static final int KEY_LEN_AES_256 = 256; - - /** @hide */ - @IntDef({ - DH_GROUP_NONE, - DH_GROUP_1024_BIT_MODP, - DH_GROUP_1536_BIT_MODP, - DH_GROUP_2048_BIT_MODP, - DH_GROUP_3072_BIT_MODP, - DH_GROUP_4096_BIT_MODP - }) - public @interface DhGroup {} - - /** None Diffie-Hellman Group. */ - public static final int DH_GROUP_NONE = 0; - /** - * 1024-bit MODP Diffie-Hellman Group. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int DH_GROUP_1024_BIT_MODP = 2; - /** - * 1536-bit MODP Diffie-Hellman Group. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int DH_GROUP_1536_BIT_MODP = 5; - /** - * 2048-bit MODP Diffie-Hellman Group. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int DH_GROUP_2048_BIT_MODP = 14; - /** - * 3072-bit MODP Diffie-Hellman Group. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int DH_GROUP_3072_BIT_MODP = 15; - /** - * 4096-bit MODP Diffie-Hellman Group. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int DH_GROUP_4096_BIT_MODP = 16; - - /** @hide */ - @IntDef({ENCRYPTION_ALGORITHM_AES_CBC, ENCRYPTION_ALGORITHM_AES_CTR}) - public @interface EncryptionAlgorithm {} - - /** - * AES-CBC Encryption/Ciphering Algorithm. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; - - /** - * AES-CTR Encryption/Ciphering Algorithm. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int ENCRYPTION_ALGORITHM_AES_CTR = 13; - - /** @hide */ - @IntDef({ - INTEGRITY_ALGORITHM_NONE, - INTEGRITY_ALGORITHM_HMAC_SHA1_96, - INTEGRITY_ALGORITHM_AES_XCBC_96, - INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, - INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, - INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 - }) - public @interface IntegrityAlgorithm {} - - /** None Authentication/Integrity Algorithm. */ - public static final int INTEGRITY_ALGORITHM_NONE = 0; - /** - * HMAC-SHA1 Authentication/Integrity Algorithm. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; - /** - * AES-XCBC-96 Authentication/Integrity Algorithm. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; - /** - * HMAC-SHA256 Authentication/Integrity Algorithm with 128-bit truncation. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; - /** - * HMAC-SHA384 Authentication/Integrity Algorithm with 192-bit truncation. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; - /** - * HMAC-SHA512 Authentication/Integrity Algorithm with 256-bit truncation. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; - - /** @hide */ - @IntDef({ - PSEUDORANDOM_FUNCTION_HMAC_SHA1, - PSEUDORANDOM_FUNCTION_AES128_XCBC, - PSEUDORANDOM_FUNCTION_SHA2_256, - PSEUDORANDOM_FUNCTION_SHA2_384, - PSEUDORANDOM_FUNCTION_SHA2_512 - }) - public @interface PseudorandomFunction {} - - /** - * HMAC-SHA1 Pseudorandom Function. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; - /** - * AES128-XCBC Pseudorandom Function. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; - /** - * HMAC-SHA2-256 Pseudorandom Function. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int PSEUDORANDOM_FUNCTION_SHA2_256 = 5; - /** - * HMAC-SHA2-384 Pseudorandom Function. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int PSEUDORANDOM_FUNCTION_SHA2_384 = 6; - /** - * HMAC-SHA2-384 Pseudorandom Function. - * - * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key - * Exchange Protocol Version 2 (IKEv2)</a> - */ - public static final int PSEUDORANDOM_FUNCTION_SHA2_512 = 7; - - /** @hide */ @IntDef({ID_TYPE_FQDN, ID_TYPE_RFC822_ADDR, ID_TYPE_KEY_ID}) public @interface IkeIdType {} @@ -4553,31 +4427,33 @@ public class CarrierConfigManager { defaults.putIntArray( KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY, new int[] { - DH_GROUP_1024_BIT_MODP, DH_GROUP_1536_BIT_MODP, DH_GROUP_2048_BIT_MODP + SaProposal.DH_GROUP_1024_BIT_MODP, + SaProposal.DH_GROUP_1536_BIT_MODP, + SaProposal.DH_GROUP_2048_BIT_MODP }); defaults.putIntArray( KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY, - new int[] {ENCRYPTION_ALGORITHM_AES_CBC}); + new int[] {SaProposal.ENCRYPTION_ALGORITHM_AES_CBC}); defaults.putIntArray( KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY, - new int[] {ENCRYPTION_ALGORITHM_AES_CBC}); + new int[] {SaProposal.ENCRYPTION_ALGORITHM_AES_CBC}); defaults.putIntArray( KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY, new int[] { - INTEGRITY_ALGORITHM_AES_XCBC_96, - INTEGRITY_ALGORITHM_HMAC_SHA1_96, - INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, - INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, - INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, + SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96, + SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96, + SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, + SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, + SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, }); defaults.putIntArray( KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY, new int[] { - PSEUDORANDOM_FUNCTION_HMAC_SHA1, - PSEUDORANDOM_FUNCTION_AES128_XCBC, - PSEUDORANDOM_FUNCTION_SHA2_256, - PSEUDORANDOM_FUNCTION_SHA2_384, - PSEUDORANDOM_FUNCTION_SHA2_512 + SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1, + SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC, + SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256, + SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384, + SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512 }); defaults.putInt(KEY_EPDG_AUTHENTICATION_METHOD_INT, AUTHENTICATION_METHOD_EAP_ONLY); @@ -4587,16 +4463,28 @@ public class CarrierConfigManager { defaults.putInt(KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT, 20); defaults.putIntArray( KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY, - new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256}); + new int[] { + SaProposal.KEY_LEN_AES_128, + SaProposal.KEY_LEN_AES_192, + SaProposal.KEY_LEN_AES_256}); defaults.putIntArray( KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY, - new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256}); + new int[] { + SaProposal.KEY_LEN_AES_128, + SaProposal.KEY_LEN_AES_192, + SaProposal.KEY_LEN_AES_256}); defaults.putIntArray( KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY, - new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256}); + new int[] { + SaProposal.KEY_LEN_AES_128, + SaProposal.KEY_LEN_AES_192, + SaProposal.KEY_LEN_AES_256}); defaults.putIntArray( KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY, - new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256}); + new int[] { + SaProposal.KEY_LEN_AES_128, + SaProposal.KEY_LEN_AES_192, + SaProposal.KEY_LEN_AES_256}); defaults.putIntArray( KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY, new int[] {EPDG_ADDRESS_PLMN, EPDG_ADDRESS_STATIC}); @@ -5011,6 +4899,9 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL, true); sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL, true); sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_ON_PEER_BOOL, true); + sDefaults.putBoolean(KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL, false); + sDefaults.putBoolean(KEY_SUPPORTS_SDP_NEGOTIATION_OF_D2D_RTP_HEADER_EXTENSIONS_BOOL, false); + sDefaults.putBoolean(KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL, false); sDefaults.putBoolean(KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL, false); sDefaults.putBoolean(KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL, false); sDefaults.putInt(KEY_IMS_CONFERENCE_SIZE_LIMIT_INT, 5); diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index cf4e6779b363..2d5f5fb58306 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -416,7 +416,7 @@ public class SubscriptionManager { * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the * subscription cross sim calling enabled - * {@link ImsMmTelManager#isCrossSimCallingEnabledByUser()} + * {@link ImsMmTelManager#isCrossSimCallingEnabled()} * while your app is running. You can also use a {@link android.app.job.JobService} * to ensure your app * is notified of changes to the {@link Uri} even when it is not running. diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index c48bd211fac2..3cb72b5e0c0d 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -14618,12 +14618,11 @@ public class TelephonyManager { * {@link #NR_DUAL_CONNECTIVITY_DISABLE_IMMEDIATE} * </ol> * @return operation result. - * <p>Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} * @throws IllegalStateException if the Telephony process is not currently available. * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public @EnableNrDualConnectivityResult int setNrDualConnectivityState( @NrDualConnectivityState int nrDualConnectivityState) { try { diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java index ca1f861f9808..363e47a6d242 100644 --- a/telephony/java/android/telephony/data/DataServiceCallback.java +++ b/telephony/java/android/telephony/data/DataServiceCallback.java @@ -254,15 +254,15 @@ public class DataServiceCallback { } /** - * The APN is throttled for the duration specified in - * {@link DataCallResponse#getRetryDurationMillis}. Calling this method unthrottles that - * APN. + * Unthrottles the APN on the current transport. There is no matching "APN throttle" method. + * Instead, the APN is throttled for the time specified in + * {@link DataCallResponse#getRetryDurationMillis}. * <p/> * see: {@link DataCallResponse#getRetryDurationMillis} * * @param apn Access Point Name defined by the carrier. */ - public void onApnUnthrottled(@NonNull String apn) { + public void onApnUnthrottled(final @NonNull String apn) { if (mCallback != null) { try { if (DBG) Rlog.d(TAG, "onApnUnthrottled"); diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java index 041edc00c4d2..406c38bf60ef 100644 --- a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java +++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java @@ -184,16 +184,6 @@ public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessi mRemoteAddresses = Collections.unmodifiableList(remoteAddresses); } - /** - * Creates attributes based off of a parcel - * @param in the parcel - * @return the attributes - */ - @NonNull - public static EpsBearerQosSessionAttributes create(@NonNull final Parcel in) { - return new EpsBearerQosSessionAttributes(in); - } - @Override public int describeContents() { return 0; diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index fcb4782c7f62..4b2829685d66 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -1018,7 +1018,7 @@ public class ImsMmTelManager implements RegistrationManager { @RequiresPermission(anyOf = { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) - public boolean isCrossSimCallingEnabledByUser() throws ImsException { + public boolean isCrossSimCallingEnabled() throws ImsException { ITelephony iTelephony = getITelephony(); if (iTelephony == null) { throw new ImsException("Could not find Telephony Service.", @@ -1058,7 +1058,7 @@ public class ImsMmTelManager implements RegistrationManager { * the IMS service is not available. * @param isEnabled true if the user's setting for Voice over Cross SIM is enabled, * false otherwise - * @see #isCrossSimCallingEnabledByUser() + * @see #isCrossSimCallingEnabled() * @hide */ @SystemApi diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml index b2719fbcac82..896ec9ae922c 100644 --- a/tests/FlickerTests/AndroidTest.xml +++ b/tests/FlickerTests/AndroidTest.xml @@ -11,6 +11,8 @@ <option name="force-skip-system-props" value="true" /> <!-- set WM tracing verbose level to all --> <option name="run-command" value="cmd window tracing level all" /> + <!-- set WM tracing to frame (avoid incomplete states) --> + <option name="run-command" value="cmd window tracing frame" /> <!-- restart launcher to activate TAPL --> <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" /> </target_preparer> diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt index fbf18d45afd8..c92d40cdd555 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt @@ -16,37 +16,12 @@ package com.android.server.wm.flicker.close -import android.app.Instrumentation -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerBuilderProvider import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.SimpleAppHelper -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible -import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible -import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow -import com.android.server.wm.flicker.wallpaperWindowBecomesVisible -import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer -import com.android.server.wm.flicker.noUncoveredRegions -import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry -import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.repetitions -import com.android.server.wm.flicker.startRotation -import org.junit.Assume import org.junit.FixMethodOrder -import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -59,110 +34,15 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class CloseAppBackButtonTest(private val testSpec: FlickerTestParameter) { - private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() - private val testApp = SimpleAppHelper(instrumentation) - - @FlickerBuilderProvider - fun buildFlicker(): FlickerBuilder { - return FlickerBuilder(instrumentation).apply { - withTestName { testSpec.name } - repeat { testSpec.config.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - } - eachRun { - this.setRotation(testSpec.config.startRotation) - testApp.launchViaIntent(wmHelper) - } - } +class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) { + override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit + get() = { + super.transition(this, it) transitions { device.pressBack() wmHelper.waitForHomeActivityVisible() } - teardown { - eachRun { - this.setRotation(Surface.ROTATION_0) - } - test { - testApp.exit() - } - } } - } - - @Presubmit - @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() - - @Presubmit - @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() - - @Presubmit - @Test - fun launcherReplacesAppWindowAsTopWindow() = - testSpec.launcherReplacesAppWindowAsTopWindow(testApp) - - @Presubmit - @Test - fun wallpaperWindowBecomesVisible() = testSpec.wallpaperWindowBecomesVisible() - - @Presubmit - @Test - fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation, - Surface.ROTATION_0) - - @Presubmit - @Test - fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() - - @Presubmit - @Test - fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() - - @Presubmit - @Test - fun wallpaperLayerReplacesAppLayer() = testSpec.wallpaperLayerReplacesAppLayer(testApp) - - @Presubmit - @Test - fun navBarLayerRotatesAndScales() { - Assume.assumeFalse(testSpec.isRotated) - testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) - } - - @FlakyTest - @Test - fun navBarLayerRotatesAndScales_Flaky() { - Assume.assumeTrue(testSpec.isRotated) - testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) - } - - @Presubmit - @Test - fun statusBarLayerRotatesScales() { - Assume.assumeFalse(testSpec.isRotated) - testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) - } - - @FlakyTest - @Test - fun statusBarLayerRotatesScales_Flaky() { - Assume.assumeTrue(testSpec.isRotated) - testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) - } - - @FlakyTest(bugId = 173684672) - @Test - fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() - - @FlakyTest(bugId = 173684672) - @Test - fun visibleLayersShownMoreThanOneConsecutiveEntry() = - testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt index 08d2b7c206bf..1f880f61d65e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt @@ -16,37 +16,12 @@ package com.android.server.wm.flicker.close -import android.app.Instrumentation -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerBuilderProvider import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.SimpleAppHelper -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible -import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible -import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow -import com.android.server.wm.flicker.wallpaperWindowBecomesVisible -import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer -import com.android.server.wm.flicker.noUncoveredRegions -import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry -import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.repetitions -import com.android.server.wm.flicker.startRotation -import org.junit.Assume import org.junit.FixMethodOrder -import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -59,110 +34,15 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class CloseAppHomeButtonTest(private val testSpec: FlickerTestParameter) { - private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() - private val testApp = SimpleAppHelper(instrumentation) - - @FlickerBuilderProvider - fun buildFlicker(): FlickerBuilder { - return FlickerBuilder(instrumentation).apply { - withTestName { testSpec.name } - repeat { testSpec.config.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - } - eachRun { - testApp.launchViaIntent(wmHelper) - this.setRotation(testSpec.config.startRotation) - } - } +class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) { + override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit + get() = { + super.transition(this, it) transitions { device.pressHome() wmHelper.waitForHomeActivityVisible() } - teardown { - eachRun { - this.setRotation(Surface.ROTATION_0) - } - test { - testApp.exit() - } - } } - } - - @Presubmit - @Test - fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible() - - @Presubmit - @Test - fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() - - @Presubmit - @Test - fun launcherReplacesAppWindowAsTopWindow() = - testSpec.launcherReplacesAppWindowAsTopWindow(testApp) - - @Presubmit - @Test - fun wallpaperWindowBecomesVisible() = testSpec.wallpaperWindowBecomesVisible() - - @Presubmit - @Test - fun noUncoveredRegions() = testSpec.noUncoveredRegions( - testSpec.config.startRotation, Surface.ROTATION_0) - - @Presubmit - @Test - fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible() - - @Presubmit - @Test - fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible() - - @Presubmit - @Test - fun wallpaperLayerReplacesAppLayer() = testSpec.wallpaperLayerReplacesAppLayer(testApp) - - @Presubmit - @Test - fun navBarLayerRotatesAndScales() { - Assume.assumeFalse(testSpec.isRotated) - testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) - } - - @FlakyTest - @Test - fun navBarLayerRotatesAndScales_Flaky() { - Assume.assumeTrue(testSpec.isRotated) - testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) - } - - @Presubmit - @Test - fun statusBarLayerRotatesScales() { - Assume.assumeFalse(testSpec.isRotated) - testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) - } - - @FlakyTest - @Test - fun statusBarLayerRotatesScales_Flaky() { - Assume.assumeTrue(testSpec.isRotated) - testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) - } - - @FlakyTest(bugId = 173689015) - @Test - fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() - - @FlakyTest(bugId = 173689015) - @Test - fun visibleLayersShownMoreThanOneConsecutiveEntry() = - testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() companion object { @Parameterized.Parameters(name = "{0}") 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 new file mode 100644 index 000000000000..fef49d9433a8 --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.flicker.close + +import android.app.Instrumentation +import android.platform.test.annotations.Presubmit +import android.view.Surface +import androidx.test.filters.FlakyTest +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.helpers.SimpleAppHelper +import com.android.server.wm.flicker.helpers.StandardAppHelper +import com.android.server.wm.flicker.helpers.setRotation +import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow +import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.navBarLayerRotatesAndScales +import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.noUncoveredRegions +import com.android.server.wm.flicker.startRotation +import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.statusBarLayerRotatesScales +import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry +import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry +import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer +import com.android.server.wm.flicker.wallpaperWindowBecomesVisible +import org.junit.Assume +import org.junit.Test + +abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) { + protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation) + protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = { + setup { + eachRun { + testApp.launchViaIntent(wmHelper) + this.setRotation(testSpec.config.startRotation) + } + } + teardown { + test { + testApp.exit() + } + } + } + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + transition(testSpec.config) + } + } + + @Presubmit + @Test + open fun navBarWindowIsAlwaysVisible() { + testSpec.navBarWindowIsAlwaysVisible() + } + + @Presubmit + @Test + open fun statusBarWindowIsAlwaysVisible() { + testSpec.statusBarWindowIsAlwaysVisible() + } + + @Presubmit + @Test + open fun navBarLayerIsAlwaysVisible() { + testSpec.navBarLayerIsAlwaysVisible() + } + + @Presubmit + @Test + open fun statusBarLayerIsAlwaysVisible() { + testSpec.statusBarLayerIsAlwaysVisible() + } + + @Presubmit + @Test + open fun navBarLayerRotatesAndScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + open fun navBarLayerRotatesAndScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + open fun statusBarLayerRotatesScales() { + Assume.assumeFalse(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest + @Test + open fun statusBarLayerRotatesScales_Flaky() { + Assume.assumeTrue(testSpec.isRotated) + testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @FlakyTest(bugId = 173689015) + @Test + open fun visibleWindowsShownMoreThanOneConsecutiveEntry() { + testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() + } + + @FlakyTest(bugId = 173689015) + @Test + open fun visibleLayersShownMoreThanOneConsecutiveEntry() { + testSpec.visibleLayersShownMoreThanOneConsecutiveEntry() + } + + @Presubmit + @Test + open fun noUncoveredRegions() { + testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0) + } + + @Presubmit + @Test + open fun launcherReplacesAppWindowAsTopWindow() { + testSpec.launcherReplacesAppWindowAsTopWindow(testApp) + } + + @Presubmit + @Test + open fun wallpaperWindowBecomesVisible() { + testSpec.wallpaperWindowBecomesVisible() + } + + @Presubmit + @Test + open fun wallpaperLayerReplacesAppLayer() { + testSpec.wallpaperLayerReplacesAppLayer(testApp) + } +}
\ No newline at end of file diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java index d6846faa5c00..e121b68ca8fa 100644 --- a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java +++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java @@ -94,17 +94,16 @@ public class PlatformCompatChangeRule extends CoreCompatChangeRule { if (platformCompat == null) { throw new IllegalStateException("Could not get IPlatformCompat service!"); } - uiAutomation.adoptShellPermissionIdentity( - Manifest.permission.LOG_COMPAT_CHANGE, - Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG, - Manifest.permission.READ_COMPAT_CHANGE_CONFIG); + adoptShellPermissions(uiAutomation); Compatibility.setOverrides(mConfig); try { platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig), packageName); try { + uiAutomation.dropShellPermissionIdentity(); mTestStatement.evaluate(); } finally { + adoptShellPermissions(uiAutomation); platformCompat.clearOverridesForTest(packageName); } } catch (RemoteException e) { @@ -114,5 +113,12 @@ public class PlatformCompatChangeRule extends CoreCompatChangeRule { Compatibility.clearOverrides(); } } + + private static void adoptShellPermissions(UiAutomation uiAutomation) { + uiAutomation.adoptShellPermissionIdentity( + Manifest.permission.LOG_COMPAT_CHANGE, + Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG, + Manifest.permission.READ_COMPAT_CHANGE_CONFIG); + } } } diff --git a/tests/RollbackTest/MultiUserRollbackTest.xml b/tests/RollbackTest/MultiUserRollbackTest.xml index 2f62af1856da..8fa0510d9e71 100644 --- a/tests/RollbackTest/MultiUserRollbackTest.xml +++ b/tests/RollbackTest/MultiUserRollbackTest.xml @@ -20,6 +20,8 @@ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" /> <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" /> <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" /> + <option name="run-command" value="setprop persist.rollback.is_test 1" /> + <option name="teardown-command" value="setprop persist.rollback.is_test 0" /> </target_preparer> <test class="com.android.tradefed.testtype.HostTest" > <option name="class" value="com.android.tests.rollback.host.MultiUserRollbackTest" /> diff --git a/tests/RollbackTest/NetworkStagedRollbackTest.xml b/tests/RollbackTest/NetworkStagedRollbackTest.xml index 2ab907a59298..13f603140aee 100644 --- a/tests/RollbackTest/NetworkStagedRollbackTest.xml +++ b/tests/RollbackTest/NetworkStagedRollbackTest.xml @@ -24,6 +24,8 @@ <option name="run-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es package "com.google.android.gms.platformconfigurator" --es user '\\*' --esa flags "ModuleConfig__versioned_immediate_commit_packages" --esa types "bytes" --esa values "Cm5vdGFwYWNrYWdlOgA=" com.google.android.gms" /> <option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package "com.google.android.gms.platformconfigurator" --es user '\*' --esa flag "ModuleConfig__immediate_commit_packages" com.google.android.gms" /> <option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package "com.google.android.gms.platformconfigurator" --es user '\*' --esa flag "ModuleConfig__versioned_immediate_commit_packages" com.google.android.gms" /> + <option name="run-command" value="setprop persist.rollback.is_test 1" /> + <option name="teardown-command" value="setprop persist.rollback.is_test 0" /> </target_preparer> <test class="com.android.tradefed.testtype.HostTest" > <option name="class" value="com.android.tests.rollback.host.NetworkStagedRollbackTest" /> diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml index 7b85cc84f1f5..fbb6e46e1721 100644 --- a/tests/RollbackTest/RollbackTest.xml +++ b/tests/RollbackTest/RollbackTest.xml @@ -27,6 +27,8 @@ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" /> <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" /> <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" /> + <option name="run-command" value="setprop persist.rollback.is_test 1" /> + <option name="teardown-command" value="setprop persist.rollback.is_test 0" /> </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.tests.rollback" /> diff --git a/tests/RollbackTest/StagedRollbackTest.xml b/tests/RollbackTest/StagedRollbackTest.xml index 83fef8e0a04b..0ca4dafae59d 100644 --- a/tests/RollbackTest/StagedRollbackTest.xml +++ b/tests/RollbackTest/StagedRollbackTest.xml @@ -24,6 +24,8 @@ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" /> <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" /> <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" /> + <option name="run-command" value="setprop persist.rollback.is_test 1" /> + <option name="teardown-command" value="setprop persist.rollback.is_test 0" /> </target_preparer> <test class="com.android.tradefed.testtype.HostTest" > <option name="class" value="com.android.tests.rollback.host.StagedRollbackTest" /> diff --git a/tests/net/Android.bp b/tests/net/Android.bp index 7f0318a135dc..e1a424f214a5 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -79,6 +79,7 @@ android_test { "android.test.runner", "android.test.base", "android.test.mock", + "ServiceConnectivityResources", ], jni_libs: [ "libservice-connectivity", diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING index 89fc6ea2c47b..d659688700d3 100644 --- a/tests/net/TEST_MAPPING +++ b/tests/net/TEST_MAPPING @@ -9,6 +9,23 @@ "name": "FrameworksNetDeflakeTest" } ], + "auto-postsubmit": [ + // Test tag for automotive targets. These are only running in postsubmit so as to harden the + // automotive targets to avoid introducing additional test flake and build time. The plan for + // presubmit testing for auto is to augment the existing tests to cover auto use cases as well. + // Additionally, this tag is used in targeted test suites to limit resource usage on the test + // infra during the hardening phase. + // TODO: this tag to be removed once the above is no longer an issue. + { + "name": "FrameworksNetTests" + }, + { + "name": "FrameworksNetIntegrationTests" + }, + { + "name": "FrameworksNetDeflakeTest" + } + ], "imports": [ { "path": "cts/tests/tests/net" diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java index ddc31bfc20b8..0dfec7592274 100644 --- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java @@ -28,6 +28,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; @@ -44,6 +45,10 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES; import static android.os.Process.INVALID_UID; +import static com.android.modules.utils.build.SdkLevel.isAtLeastR; +import static com.android.modules.utils.build.SdkLevel.isAtLeastS; +import static com.android.testutils.MiscAsserts.assertEmpty; +import static com.android.testutils.MiscAsserts.assertThrows; import static com.android.testutils.ParcelUtils.assertParcelSane; import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; import static com.android.testutils.ParcelUtils.parcelingRoundTrip; @@ -67,7 +72,7 @@ import android.util.ArraySet; import androidx.test.runner.AndroidJUnit4; -import com.android.modules.utils.build.SdkLevel; +import com.android.testutils.CompatUtil; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; @@ -84,6 +89,9 @@ import java.util.Set; public class NetworkCapabilitiesTest { private static final String TEST_SSID = "TEST_SSID"; private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID"; + private static final int TEST_SUBID1 = 1; + private static final int TEST_SUBID2 = 2; + private static final int TEST_SUBID3 = 3; @Rule public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule(); @@ -91,14 +99,6 @@ public class NetworkCapabilitiesTest { private DiscoverySession mDiscoverySession = Mockito.mock(DiscoverySession.class); private PeerHandle mPeerHandle = Mockito.mock(PeerHandle.class); - private boolean isAtLeastR() { - return SdkLevel.isAtLeastR(); - } - - private boolean isAtLeastS() { - return SdkLevel.isAtLeastS(); - } - @Test public void testMaybeMarkCapabilitiesRestricted() { // verify EIMS is restricted @@ -211,7 +211,7 @@ public class NetworkCapabilitiesTest { nc1 = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI); nc2 = new NetworkCapabilities() .addTransportType(TRANSPORT_WIFI) - .setNetworkSpecifier(new EthernetNetworkSpecifier("eth42")); + .setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier("eth42")); assertNotEquals("", nc1.describeImmutableDifferences(nc2)); assertEquals("", nc1.describeImmutableDifferences(nc1)); } @@ -304,7 +304,9 @@ public class NetworkCapabilitiesTest { .setUids(uids) .addCapability(NET_CAPABILITY_EIMS) .addCapability(NET_CAPABILITY_NOT_METERED); - if (isAtLeastR()) { + if (isAtLeastS()) { + netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)); + } else if (isAtLeastR()) { netCap.setOwnerUid(123); netCap.setAdministratorUids(new int[] {5, 11}); } @@ -379,7 +381,7 @@ public class NetworkCapabilitiesTest { private void testParcelSane(NetworkCapabilities cap) { if (isAtLeastS()) { - assertParcelSane(cap, 16); + assertParcelSane(cap, 17); } else if (isAtLeastR()) { assertParcelSane(cap, 15); } else { @@ -613,6 +615,20 @@ public class NetworkCapabilitiesTest { assertFalse(nc2.appliesToUid(12)); assertTrue(nc1.appliesToUid(22)); assertTrue(nc2.appliesToUid(22)); + + // Verify the subscription id list can be combined only when they are equal. + if (isAtLeastS()) { + nc1.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)); + nc2.setSubIds(Set.of(TEST_SUBID2)); + assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1)); + + nc2.setSubIds(Set.of()); + assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1)); + + nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1)); + nc2.combineCapabilities(nc1); + assertEquals(Set.of(TEST_SUBID2, TEST_SUBID1), nc2.getSubIds()); + } } @Test @IgnoreUpTo(Build.VERSION_CODES.Q) @@ -671,7 +687,7 @@ public class NetworkCapabilitiesTest { NetworkCapabilities nc1 = new NetworkCapabilities(); nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI); try { - nc1.setNetworkSpecifier(new EthernetNetworkSpecifier("eth0")); + nc1.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier("eth0")); fail("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!"); } catch (IllegalStateException expected) { // empty @@ -680,7 +696,7 @@ public class NetworkCapabilitiesTest { // Sequence 2: Transport + NetworkSpecifier + Transport NetworkCapabilities nc2 = new NetworkCapabilities(); nc2.addTransportType(TRANSPORT_CELLULAR).setNetworkSpecifier( - new EthernetNetworkSpecifier("testtap3")); + CompatUtil.makeEthernetNetworkSpecifier("testtap3")); try { nc2.addTransportType(TRANSPORT_WIFI); fail("Cannot set a second TransportType of a network which has a NetworkSpecifier!"); @@ -761,6 +777,24 @@ public class NetworkCapabilitiesTest { nc1.setUids(uidRange(10, 13)); nc2.set(nc1); // Overwrites, as opposed to combineCapabilities assertEquals(nc1, nc2); + + if (isAtLeastS()) { + assertThrows(NullPointerException.class, () -> nc1.setSubIds(null)); + nc1.setSubIds(Set.of()); + nc2.set(nc1); + assertEquals(nc1, nc2); + + nc1.setSubIds(Set.of(TEST_SUBID1)); + nc2.set(nc1); + assertEquals(nc1, nc2); + + nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1)); + nc2.set(nc1); + assertEquals(nc1, nc2); + + nc2.setSubIds(Set.of(TEST_SUBID3, TEST_SUBID2)); + assertNotEquals(nc1, nc2); + } } @Test @@ -841,6 +875,50 @@ public class NetworkCapabilitiesTest { } catch (NullPointerException expected) { } } + private static NetworkCapabilities capsWithSubIds(Integer ... subIds) { + // Since the NetworkRequest would put NOT_VCN_MANAGED capabilities in general, for + // every NetworkCapabilities that simulates networks needs to add it too in order to + // satisfy these requests. + final NetworkCapabilities nc = new NetworkCapabilities.Builder() + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .setSubIds(new ArraySet<>(subIds)).build(); + assertEquals(new ArraySet<>(subIds), nc.getSubIds()); + return nc; + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.R) + public void testSubIds() throws Exception { + final NetworkCapabilities ncWithoutId = capsWithSubIds(); + final NetworkCapabilities ncWithId = capsWithSubIds(TEST_SUBID1); + final NetworkCapabilities ncWithOtherIds = capsWithSubIds(TEST_SUBID1, TEST_SUBID3); + final NetworkCapabilities ncWithoutRequestedIds = capsWithSubIds(TEST_SUBID3); + + final NetworkRequest requestWithoutId = new NetworkRequest.Builder().build(); + assertEmpty(requestWithoutId.networkCapabilities.getSubIds()); + final NetworkRequest requestWithIds = new NetworkRequest.Builder() + .setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)).build(); + assertEquals(Set.of(TEST_SUBID1, TEST_SUBID2), + requestWithIds.networkCapabilities.getSubIds()); + + assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutId)); + assertTrue(requestWithIds.canBeSatisfiedBy(ncWithOtherIds)); + assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutRequestedIds)); + assertTrue(requestWithIds.canBeSatisfiedBy(ncWithId)); + assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithoutId)); + assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithId)); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.R) + public void testEqualsSubIds() throws Exception { + assertEquals(capsWithSubIds(), capsWithSubIds()); + assertNotEquals(capsWithSubIds(), capsWithSubIds(TEST_SUBID1)); + assertEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID1)); + assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2)); + assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2, TEST_SUBID1)); + assertEquals(capsWithSubIds(TEST_SUBID1, TEST_SUBID2), + capsWithSubIds(TEST_SUBID2, TEST_SUBID1)); + } + @Test public void testLinkBandwidthKbps() { final NetworkCapabilities nc = new NetworkCapabilities(); @@ -1021,5 +1099,11 @@ public class NetworkCapabilitiesTest { fail("Should not set null into NetworkCapabilities.Builder"); } catch (NullPointerException expected) { } assertEquals(nc, new NetworkCapabilities.Builder(nc).build()); + + if (isAtLeastS()) { + final NetworkCapabilities nc2 = new NetworkCapabilities.Builder() + .setSubIds(Set.of(TEST_SUBID1)).build(); + assertEquals(Set.of(TEST_SUBID1), nc2.getSubIds()); + } } } diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt index 71a7a7c4ebd9..340e6f963137 100644 --- a/tests/net/common/java/android/net/NetworkProviderTest.kt +++ b/tests/net/common/java/android/net/NetworkProviderTest.kt @@ -27,6 +27,7 @@ import android.os.HandlerThread import android.os.Looper import androidx.test.InstrumentationRegistry import com.android.net.module.util.ArrayTrackRecord +import com.android.testutils.CompatUtil import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.DevSdkIgnoreRunner import com.android.testutils.isDevSdkInRange @@ -102,7 +103,8 @@ class NetworkProviderTest { mCm.registerNetworkProvider(provider) assertNotEquals(provider.getProviderId(), NetworkProvider.ID_NONE) - val specifier = EthernetNetworkSpecifier(UUID.randomUUID().toString()) + val specifier = CompatUtil.makeTestNetworkSpecifier( + UUID.randomUUID().toString()) val nr: NetworkRequest = NetworkRequest.Builder() .addTransportType(TRANSPORT_TEST) .setNetworkSpecifier(specifier) @@ -183,7 +185,8 @@ class NetworkProviderTest { mCm.registerNetworkProvider(provider) - val specifier = EthernetNetworkSpecifier(UUID.randomUUID().toString()) + val specifier = CompatUtil.makeTestNetworkSpecifier( + UUID.randomUUID().toString()) val nr: NetworkRequest = NetworkRequest.Builder() .addTransportType(TRANSPORT_TEST) .setNetworkSpecifier(specifier) diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java index e1da3d0ae2b3..01d8186c7d1b 100644 --- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java @@ -64,6 +64,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { private final HandlerThread mHandlerThread; private final Context mContext; private final String mLogTag; + private final NetworkAgentConfig mNetworkAgentConfig; private final ConditionVariable mDisconnected = new ConditionVariable(); private final ConditionVariable mPreventReconnectReceived = new ConditionVariable(); @@ -115,13 +116,19 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { mHandlerThread = new HandlerThread(mLogTag); mHandlerThread.start(); - mNetworkAgent = makeNetworkAgent(linkProperties, type, typeName); + // extraInfo is set to "" by default in NetworkAgentConfig. + final String extraInfo = (transport == TRANSPORT_CELLULAR) ? "internet.apn" : ""; + mNetworkAgentConfig = new NetworkAgentConfig.Builder() + .setLegacyType(type) + .setLegacyTypeName(typeName) + .setLegacyExtraInfo(extraInfo) + .build(); + mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig); } protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties, - final int type, final String typeName) - throws Exception { - return new InstrumentedNetworkAgent(this, linkProperties, type, typeName); + final NetworkAgentConfig nac) throws Exception { + return new InstrumentedNetworkAgent(this, linkProperties, nac); } public static class InstrumentedNetworkAgent extends NetworkAgent { @@ -129,11 +136,9 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { private static final String PROVIDER_NAME = "InstrumentedNetworkAgentProvider"; public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp, - final int type, final String typeName) { + NetworkAgentConfig nac) { super(wrapper.mContext, wrapper.mHandlerThread.getLooper(), wrapper.mLogTag, - wrapper.mNetworkCapabilities, lp, wrapper.mScore, - new NetworkAgentConfig.Builder() - .setLegacyType(type).setLegacyTypeName(typeName).build(), + wrapper.mNetworkCapabilities, lp, wrapper.mScore, nac, new NetworkProvider(wrapper.mContext, wrapper.mHandlerThread.getLooper(), PROVIDER_NAME)); mWrapper = wrapper; @@ -301,6 +306,14 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { return mNetworkCapabilities; } + public int getLegacyType() { + return mNetworkAgentConfig.getLegacyType(); + } + + public String getExtraInfo() { + return mNetworkAgentConfig.getLegacyExtraInfo(); + } + public @NonNull ArrayTrackRecord<CallbackType>.ReadHead getCallbackHistory() { return mCallbackHistory; } diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java index 6a09b0237a38..6fc605e269fe 100644 --- a/tests/net/java/android/net/ConnectivityManagerTest.java +++ b/tests/net/java/android/net/ConnectivityManagerTest.java @@ -220,7 +220,7 @@ public class ConnectivityManagerTest { // register callback when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(), - any(), nullable(String.class))).thenReturn(request); + anyInt(), any(), nullable(String.class))).thenReturn(request); manager.requestNetwork(request, callback, handler); // callback triggers @@ -248,7 +248,7 @@ public class ConnectivityManagerTest { // register callback when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(), - any(), nullable(String.class))).thenReturn(req1); + anyInt(), any(), nullable(String.class))).thenReturn(req1); manager.requestNetwork(req1, callback, handler); // callback triggers @@ -266,7 +266,7 @@ public class ConnectivityManagerTest { // callback can be registered again when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(), - any(), nullable(String.class))).thenReturn(req2); + anyInt(), any(), nullable(String.class))).thenReturn(req2); manager.requestNetwork(req2, callback, handler); // callback triggers @@ -289,8 +289,8 @@ public class ConnectivityManagerTest { info.targetSdkVersion = VERSION_CODES.N_MR1 + 1; when(mCtx.getApplicationInfo()).thenReturn(info); - when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), any(), - nullable(String.class))).thenReturn(request); + when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(), + any(), nullable(String.class))).thenReturn(request); Handler handler = new Handler(Looper.getMainLooper()); manager.requestNetwork(request, callback, handler); @@ -358,34 +358,34 @@ public class ConnectivityManagerTest { manager.requestNetwork(request, callback); verify(mService).requestNetwork(eq(request.networkCapabilities), - eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), + eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), eq(testPkgName), eq(testAttributionTag)); reset(mService); // Verify that register network callback does not calls requestNetwork at all. manager.registerNetworkCallback(request, callback); - verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(), + verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(), any(), any()); - verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), + verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(), eq(testPkgName), eq(testAttributionTag)); reset(mService); manager.registerDefaultNetworkCallback(callback); verify(mService).requestNetwork(eq(null), - eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), + eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), eq(testPkgName), eq(testAttributionTag)); reset(mService); - manager.requestBackgroundNetwork(request, null, callback); + Handler handler = new Handler(ConnectivityThread.getInstanceLooper()); + manager.requestBackgroundNetwork(request, handler, callback); verify(mService).requestNetwork(eq(request.networkCapabilities), - eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), + eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), eq(testPkgName), eq(testAttributionTag)); reset(mService); - Handler handler = new Handler(ConnectivityThread.getInstanceLooper()); manager.registerSystemDefaultNetworkCallback(callback, handler); verify(mService).requestNetwork(eq(null), - eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), + eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), eq(testPkgName), eq(testAttributionTag)); reset(mService); } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 2c6a21ad7570..fadd1eac14ef 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -266,7 +266,6 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.app.IBatteryStats; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; import com.android.internal.util.ArrayUtils; @@ -276,6 +275,7 @@ import com.android.internal.util.test.FakeSettingsProvider; import com.android.net.module.util.ArrayTrackRecord; import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo; import com.android.server.connectivity.ConnectivityConstants; +import com.android.server.connectivity.ConnectivityResources; import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.NetworkAgentInfo; @@ -428,7 +428,6 @@ public class ConnectivityServiceTest { @Mock DeviceIdleInternal mDeviceIdleInternal; @Mock INetworkManagementService mNetworkManagementService; @Mock NetworkStatsManager mStatsManager; - @Mock IBatteryStats mBatteryStatsService; @Mock IDnsResolver mMockDnsResolver; @Mock INetd mMockNetd; @Mock NetworkStackClient mNetworkStack; @@ -446,6 +445,7 @@ public class ConnectivityServiceTest { @Mock NetworkPolicyManager mNetworkPolicyManager; @Mock VpnProfileStore mVpnProfileStore; @Mock SystemConfigManager mSystemConfigManager; + @Mock Resources mResources; private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor = ArgumentCaptor.forClass(ResolverParamsParcel.class); @@ -473,7 +473,7 @@ public class ConnectivityServiceTest { private class MockContext extends BroadcastInterceptingContext { private final MockContentResolver mContentResolver; - @Spy private Resources mResources; + @Spy private Resources mInternalResources; private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>(); // Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant @@ -482,21 +482,15 @@ public class ConnectivityServiceTest { MockContext(Context base, ContentProvider settingsProvider) { super(base); - mResources = spy(base.getResources()); - when(mResources.getStringArray(com.android.internal.R.array.networkAttributes)). - thenReturn(new String[] { + mInternalResources = spy(base.getResources()); + when(mInternalResources.getStringArray(com.android.internal.R.array.networkAttributes)) + .thenReturn(new String[] { "wifi,1,1,1,-1,true", "mobile,0,0,0,-1,true", "mobile_mms,2,0,2,60000,true", "mobile_supl,3,0,2,60000,true", }); - when(mResources.getStringArray( - com.android.internal.R.array.config_wakeonlan_supported_interfaces)) - .thenReturn(new String[]{ - WIFI_WOL_IFNAME, - }); - mContentResolver = new MockContentResolver(); mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider); } @@ -561,7 +555,7 @@ public class ConnectivityServiceTest { @Override public Resources getResources() { - return mResources; + return mInternalResources; } @Override @@ -720,7 +714,7 @@ public class ConnectivityServiceTest { @Override protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties, - final int type, final String typeName) throws Exception { + NetworkAgentConfig nac) throws Exception { mNetworkMonitor = mock(INetworkMonitor.class); final Answer validateAnswer = inv -> { @@ -739,8 +733,8 @@ public class ConnectivityServiceTest { any() /* name */, nmCbCaptor.capture()); - final InstrumentedNetworkAgent na = new InstrumentedNetworkAgent(this, linkProperties, - type, typeName) { + final InstrumentedNetworkAgent na = + new InstrumentedNetworkAgent(this, linkProperties, nac) { @Override public void networkStatus(int status, String redirectUrl) { mRedirectUrl = redirectUrl; @@ -1456,6 +1450,8 @@ public class ConnectivityServiceTest { applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q; when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) .thenReturn(applicationInfo); + when(mPackageManager.getTargetSdkVersion(anyString())) + .thenReturn(applicationInfo.targetSdkVersion); when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]); // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not. @@ -1527,12 +1523,23 @@ public class ConnectivityServiceTest { doReturn(mSystemProperties).when(deps).getSystemProperties(); doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any()); doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt()); - doReturn(mBatteryStatsService).when(deps).getBatteryStatsService(); doAnswer(inv -> { mPolicyTracker = new WrappedMultinetworkPolicyTracker( inv.getArgument(0), inv.getArgument(1), inv.getArgument(2)); return mPolicyTracker; }).when(deps).makeMultinetworkPolicyTracker(any(), any(), any()); + doReturn(true).when(deps).getCellular464XlatEnabled(); + + doReturn(60000).when(mResources).getInteger( + com.android.connectivity.resources.R.integer.config_networkTransitionTimeout); + doReturn("").when(mResources).getString( + com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl); + doReturn(new String[]{ WIFI_WOL_IFNAME }).when(mResources).getStringArray( + com.android.connectivity.resources.R.array.config_wakeonlan_supported_interfaces); + final com.android.server.connectivity.ConnectivityResources connRes = mock( + ConnectivityResources.class); + doReturn(mResources).when(connRes).get(); + doReturn(connRes).when(deps).getResources(any()); return deps; } @@ -1743,11 +1750,29 @@ public class ConnectivityServiceTest { return expected; } + private boolean extraInfoInBroadcastHasExpectedNullness(NetworkInfo ni) { + final DetailedState state = ni.getDetailedState(); + if (state == DetailedState.CONNECTED && ni.getExtraInfo() == null) return false; + // Expect a null extraInfo if the network is CONNECTING, because a CONNECTIVITY_ACTION + // broadcast with a state of CONNECTING only happens due to legacy VPN lockdown, which also + // nulls out extraInfo. + if (state == DetailedState.CONNECTING && ni.getExtraInfo() != null) return false; + // Can't make any assertions about DISCONNECTED broadcasts. When a network actually + // disconnects, disconnectAndDestroyNetwork sets its state to DISCONNECTED and its extraInfo + // to null. But if the DISCONNECTED broadcast is just simulated by LegacyTypeTracker due to + // a network switch, extraInfo will likely be populated. + // This is likely a bug in CS, but likely not one we can fix without impacting apps. + return true; + } + private ExpectedBroadcast expectConnectivityAction(int type, NetworkInfo.DetailedState state) { - return registerConnectivityBroadcastThat(1, intent -> - type == intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) && state.equals( - ((NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO)) - .getDetailedState())); + return registerConnectivityBroadcastThat(1, intent -> { + final int actualType = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1); + final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO); + return type == actualType + && state == ni.getDetailedState() + && extraInfoInBroadcastHasExpectedNullness(ni); + }); } @Test @@ -3733,8 +3758,8 @@ public class ConnectivityServiceTest { networkCapabilities.addTransportType(TRANSPORT_WIFI) .setNetworkSpecifier(new MatchAllNetworkSpecifier()); mService.requestNetwork(networkCapabilities, NetworkRequest.Type.REQUEST.ordinal(), - null, 0, null, ConnectivityManager.TYPE_WIFI, mContext.getPackageName(), - getAttributionTag()); + null, 0, null, ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE, + mContext.getPackageName(), getAttributionTag()); }); class NonParcelableSpecifier extends NetworkSpecifier { @@ -4011,7 +4036,8 @@ public class ConnectivityServiceTest { grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid()); final TestNetworkCallback cellBgCallback = new TestNetworkCallback(); mCm.requestBackgroundNetwork(new NetworkRequest.Builder() - .addTransportType(TRANSPORT_CELLULAR).build(), null, cellBgCallback); + .addTransportType(TRANSPORT_CELLULAR).build(), + mCsHandlerThread.getThreadHandler(), cellBgCallback); // Make callbacks for monitoring. final NetworkRequest request = new NetworkRequest.Builder().build(); @@ -7185,12 +7211,14 @@ public class ConnectivityServiceTest { assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertExtraInfoFromCmPresent(mCellNetworkAgent); setUidRulesChanged(RULE_REJECT_ALL); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); + assertExtraInfoFromCmBlocked(mCellNetworkAgent); // ConnectivityService should cache it not to invoke the callback again. setUidRulesChanged(RULE_REJECT_METERED); @@ -7201,12 +7229,14 @@ public class ConnectivityServiceTest { assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertExtraInfoFromCmPresent(mCellNetworkAgent); setUidRulesChanged(RULE_REJECT_METERED); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); + assertExtraInfoFromCmBlocked(mCellNetworkAgent); // Restrict the network based on UID rule and NOT_METERED capability change. mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); @@ -7215,6 +7245,7 @@ public class ConnectivityServiceTest { assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertExtraInfoFromCmPresent(mCellNetworkAgent); mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED); cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, @@ -7223,12 +7254,14 @@ public class ConnectivityServiceTest { assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); + assertExtraInfoFromCmBlocked(mCellNetworkAgent); setUidRulesChanged(RULE_ALLOW_METERED); cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertExtraInfoFromCmPresent(mCellNetworkAgent); setUidRulesChanged(RULE_NONE); cellNetworkCallback.assertNoCallback(); @@ -7239,6 +7272,7 @@ public class ConnectivityServiceTest { assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); + assertExtraInfoFromCmBlocked(mCellNetworkAgent); setRestrictBackgroundChanged(true); cellNetworkCallback.assertNoCallback(); @@ -7246,12 +7280,14 @@ public class ConnectivityServiceTest { cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertExtraInfoFromCmPresent(mCellNetworkAgent); setRestrictBackgroundChanged(false); cellNetworkCallback.assertNoCallback(); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertExtraInfoFromCmPresent(mCellNetworkAgent); mCm.unregisterNetworkCallback(cellNetworkCallback); } @@ -7310,6 +7346,15 @@ public class ConnectivityServiceTest { assertNotNull(ni); assertEquals(type, ni.getType()); assertEquals(ConnectivityManager.getNetworkTypeName(type), state, ni.getDetailedState()); + if (state == DetailedState.CONNECTED || state == DetailedState.SUSPENDED) { + assertNotNull(ni.getExtraInfo()); + } else { + // Technically speaking, a network that's in CONNECTING state will generally have a + // non-null extraInfo. This doesn't actually happen in this test because it never calls + // a legacy API while a network is connecting. When a network is in CONNECTING state + // because of legacy lockdown VPN, its extraInfo is always null. + assertNull(ni.getExtraInfo()); + } } private void assertActiveNetworkInfo(int type, DetailedState state) { @@ -7319,6 +7364,26 @@ public class ConnectivityServiceTest { checkNetworkInfo(mCm.getNetworkInfo(type), type, state); } + private void assertExtraInfoFromCm(TestNetworkAgentWrapper network, boolean present) { + final NetworkInfo niForNetwork = mCm.getNetworkInfo(network.getNetwork()); + final NetworkInfo niForType = mCm.getNetworkInfo(network.getLegacyType()); + if (present) { + assertEquals(network.getExtraInfo(), niForNetwork.getExtraInfo()); + assertEquals(network.getExtraInfo(), niForType.getExtraInfo()); + } else { + assertNull(niForNetwork.getExtraInfo()); + assertNull(niForType.getExtraInfo()); + } + } + + private void assertExtraInfoFromCmBlocked(TestNetworkAgentWrapper network) { + assertExtraInfoFromCm(network, false); + } + + private void assertExtraInfoFromCmPresent(TestNetworkAgentWrapper network) { + assertExtraInfoFromCm(network, true); + } + // Checks that each of the |agents| receive a blocked status change callback with the specified // |blocked| value, in any order. This is needed because when an event affects multiple // networks, ConnectivityService does not guarantee the order in which callbacks are fired. @@ -7633,6 +7698,7 @@ public class ConnectivityServiceTest { assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED); + assertExtraInfoFromCmBlocked(mCellNetworkAgent); // TODO: it would be nice if we could simply rely on the production code here, and have // LockdownVpnTracker start the VPN, have the VPN code register its NetworkAgent with @@ -7661,6 +7727,7 @@ public class ConnectivityServiceTest { assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + assertExtraInfoFromCmPresent(mCellNetworkAgent); assertTrue(vpnNc.hasTransport(TRANSPORT_VPN)); assertTrue(vpnNc.hasTransport(TRANSPORT_CELLULAR)); assertFalse(vpnNc.hasTransport(TRANSPORT_WIFI)); @@ -7703,6 +7770,7 @@ public class ConnectivityServiceTest { assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED); + assertExtraInfoFromCmBlocked(mWiFiNetworkAgent); // The VPN comes up again on wifi. b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED); @@ -7717,6 +7785,7 @@ public class ConnectivityServiceTest { assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + assertExtraInfoFromCmPresent(mWiFiNetworkAgent); vpnNc = mCm.getNetworkCapabilities(mMockVpn.getNetwork()); assertTrue(vpnNc.hasTransport(TRANSPORT_VPN)); assertTrue(vpnNc.hasTransport(TRANSPORT_WIFI)); @@ -7733,6 +7802,7 @@ public class ConnectivityServiceTest { assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + assertExtraInfoFromCmPresent(mWiFiNetworkAgent); b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED); mWiFiNetworkAgent.disconnect(); @@ -7812,7 +7882,6 @@ public class ConnectivityServiceTest { verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext, cellLp.getInterfaceName(), new int[] { TRANSPORT_CELLULAR }); - reset(mBatteryStatsService); final LinkProperties wifiLp = new LinkProperties(); wifiLp.setInterfaceName("wifi0"); @@ -7822,7 +7891,6 @@ public class ConnectivityServiceTest { verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext, wifiLp.getInterfaceName(), new int[] { TRANSPORT_WIFI }); - reset(mBatteryStatsService); mCellNetworkAgent.disconnect(); mWiFiNetworkAgent.disconnect(); @@ -7905,7 +7973,6 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); reset(mMockDnsResolver); reset(mMockNetd); - reset(mBatteryStatsService); // Connect with ipv6 link properties. Expect prefix discovery to be started. mCellNetworkAgent.connect(true); @@ -8268,6 +8335,45 @@ public class ConnectivityServiceTest { } @Test + public void testWith464XlatDisable() throws Exception { + doReturn(false).when(mDeps).getCellular464XlatEnabled(); + + final TestNetworkCallback callback = new TestNetworkCallback(); + final TestNetworkCallback defaultCallback = new TestNetworkCallback(); + final NetworkRequest networkRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_INTERNET) + .build(); + mCm.registerNetworkCallback(networkRequest, callback); + mCm.registerDefaultNetworkCallback(defaultCallback); + + // Bring up validated cell. + final LinkProperties cellLp = new LinkProperties(); + cellLp.setInterfaceName(MOBILE_IFNAME); + cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64")); + cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, MOBILE_IFNAME)); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + + mCellNetworkAgent.sendLinkProperties(cellLp); + mCellNetworkAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + final int cellNetId = mCellNetworkAgent.getNetwork().netId; + waitForIdle(); + + verify(mMockDnsResolver, never()).startPrefix64Discovery(cellNetId); + Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent); + assertTrue("Nat464Xlat was not IDLE", !clat.isStarted()); + + // This cannot happen because prefix discovery cannot succeed if it is never started. + mService.mResolverUnsolEventCallback.onNat64PrefixEvent( + makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, "64:ff9b::", 96)); + + // ... but still, check that even if it did, clatd would not be started. + verify(mMockNetd, never()).clatdStart(anyString(), anyString()); + assertTrue("Nat464Xlat was not IDLE", !clat.isStarted()); + } + + @Test public void testDataActivityTracking() throws Exception { final TestNetworkCallback networkCallback = new TestNetworkCallback(); final NetworkRequest networkRequest = new NetworkRequest.Builder() @@ -8659,6 +8765,7 @@ public class ConnectivityServiceTest { applicationInfo.targetSdkVersion = targetSdk; when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) .thenReturn(applicationInfo); + when(mPackageManager.getTargetSdkVersion(any())).thenReturn(targetSdk); when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle); @@ -8673,102 +8780,183 @@ public class ConnectivityServiceTest { } } - private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) { + private int getOwnerUidNetCapsPermission(int ownerUid, int callerUid, + boolean includeLocationSensitiveInfo) { final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid); return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled( - netCap, callerUid, mContext.getPackageName(), getAttributionTag()).getOwnerUid(); + netCap, includeLocationSensitiveInfo, callerUid, + mContext.getPackageName(), getAttributionTag()) + .getOwnerUid(); } - private void verifyWifiInfoCopyNetCapsForCallerPermission( - int callerUid, boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) { + private void verifyWifiInfoCopyNetCapsPermission( + int callerUid, boolean includeLocationSensitiveInfo, + boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) { final WifiInfo wifiInfo = mock(WifiInfo.class); when(wifiInfo.hasLocationSensitiveFields()).thenReturn(true); final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo); mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled( - netCap, callerUid, mContext.getPackageName(), getAttributionTag()); + netCap, includeLocationSensitiveInfo, callerUid, + mContext.getPackageName(), getAttributionTag()); verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable)); } + private void verifyOwnerUidAndWifiInfoNetCapsPermission( + boolean shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag, + boolean shouldInclLocationSensitiveOwnerUidWithIncludeFlag, + boolean shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag, + boolean shouldInclLocationSensitiveWifiInfoWithIncludeFlag) { + final int myUid = Process.myUid(); + + final int expectedOwnerUidWithoutIncludeFlag = + shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag + ? Process.myUid() : INVALID_UID; + assertEquals(expectedOwnerUidWithoutIncludeFlag, getOwnerUidNetCapsPermission( + myUid, myUid, false /* includeLocationSensitiveInfo */)); + + final int expectedOwnerUidWithIncludeFlag = + shouldInclLocationSensitiveOwnerUidWithIncludeFlag ? myUid : INVALID_UID; + assertEquals(expectedOwnerUidWithIncludeFlag, getOwnerUidNetCapsPermission( + myUid, myUid, true /* includeLocationSensitiveInfo */)); + + verifyWifiInfoCopyNetCapsPermission(myUid, + false, /* includeLocationSensitiveInfo */ + shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag); + + verifyWifiInfoCopyNetCapsPermission(myUid, + true, /* includeLocationSensitiveInfo */ + shouldInclLocationSensitiveWifiInfoWithIncludeFlag); + + } + @Test - public void testCreateForCallerWithLocationInfoSanitizedWithFineLocationAfterQ() + public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQ() throws Exception { setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); - final int myUid = Process.myUid(); - assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid)); + verifyOwnerUidAndWifiInfoNetCapsPermission( + // Ensure that we include owner uid even if the request asks to remove it since the + // app has necessary permissions and targetSdk < S. + true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ + true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ + false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ + // Ensure that we remove location info if the request asks to remove it even if the + // app has necessary permissions. + true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + ); + } + + @Test + public void testCreateWithLocationInfoSanitizedWithFineLocationPreSWithAndWithoutCallbackFlag() + throws Exception { + setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION); + + verifyOwnerUidAndWifiInfoNetCapsPermission( + // Ensure that we include owner uid even if the request asks to remove it since the + // app has necessary permissions and targetSdk < S. + true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ + true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ + false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ + // Ensure that we remove location info if the request asks to remove it even if the + // app has necessary permissions. + true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + ); + } + + @Test + public void + testCreateWithLocationInfoSanitizedWithFineLocationAfterSWithAndWithoutCallbackFlag() + throws Exception { + setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION); - verifyWifiInfoCopyNetCapsForCallerPermission(myUid, - true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */); + verifyOwnerUidAndWifiInfoNetCapsPermission( + // Ensure that we owner UID if the request asks us to remove it even if the app + // has necessary permissions since targetSdk >= S. + false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ + true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ + false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ + // Ensure that we remove location info if the request asks to remove it even if the + // app has necessary permissions. + true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + ); } @Test - public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationPreQ() + public void testCreateWithLocationInfoSanitizedWithCoarseLocationPreQ() throws Exception { setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION); - final int myUid = Process.myUid(); - assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid)); - - verifyWifiInfoCopyNetCapsForCallerPermission(myUid, - true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */); + verifyOwnerUidAndWifiInfoNetCapsPermission( + // Ensure that we owner UID if the request asks us to remove it even if the app + // has necessary permissions since targetSdk >= S. + true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ + true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ + false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ + // Ensure that we remove location info if the request asks to remove it even if the + // app has necessary permissions. + true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + ); } @Test - public void testCreateForCallerWithLocationInfoSanitizedLocationOff() throws Exception { + public void testCreateWithLocationInfoSanitizedLocationOff() throws Exception { // Test that even with fine location permission, and UIDs matching, the UID is sanitized. setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); - final int myUid = Process.myUid(); - assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid)); - - verifyWifiInfoCopyNetCapsForCallerPermission(myUid, - false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */); + verifyOwnerUidAndWifiInfoNetCapsPermission( + false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ + false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ + false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ + false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + ); } @Test - public void testCreateForCallerWithLocationInfoSanitizedWrongUid() throws Exception { + public void testCreateWithLocationInfoSanitizedWrongUid() throws Exception { // Test that even with fine location permission, not being the owner leads to sanitization. setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); final int myUid = Process.myUid(); - assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid)); - - verifyWifiInfoCopyNetCapsForCallerPermission(myUid, - true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */); + assertEquals(Process.INVALID_UID, + getOwnerUidNetCapsPermission(myUid + 1, myUid, + true /* includeLocationSensitiveInfo */)); } @Test - public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationAfterQ() + public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterQ() throws Exception { // Test that not having fine location permission leads to sanitization. setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION); - // Test that without the location permission, the owner field is sanitized. - final int myUid = Process.myUid(); - assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid)); - - verifyWifiInfoCopyNetCapsForCallerPermission(myUid, - false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */); + verifyOwnerUidAndWifiInfoNetCapsPermission( + false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ + false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ + false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ + false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + ); } @Test - public void testCreateForCallerWithLocationInfoSanitizedWithoutLocationPermission() + public void testCreateWithLocationInfoSanitizedWithoutLocationPermission() throws Exception { + // Test that not having fine location permission leads to sanitization. setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */); - // Test that without the location permission, the owner field is sanitized. - final int myUid = Process.myUid(); - assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid)); - - verifyWifiInfoCopyNetCapsForCallerPermission(myUid, - false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */); + verifyOwnerUidAndWifiInfoNetCapsPermission( + false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ + false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ + false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ + false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + ); } private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType) @@ -8973,7 +9161,7 @@ public class ConnectivityServiceTest { TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE)); return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(), nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0, - INVALID_UID, mQosCallbackTracker); + INVALID_UID, mQosCallbackTracker, new ConnectivityService.Dependencies()); } @Test @@ -9359,8 +9547,8 @@ public class ConnectivityServiceTest { assertThrows("Expect throws for invalid request type " + reqTypeInt, IllegalArgumentException.class, () -> mService.requestNetwork(nc, reqTypeInt, null, 0, null, - ConnectivityManager.TYPE_NONE, mContext.getPackageName(), - getAttributionTag()) + ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE, + mContext.getPackageName(), getAttributionTag()) ); } } @@ -10930,4 +11118,12 @@ public class ConnectivityServiceTest { verifyNoNetwork(); mCm.unregisterNetworkCallback(cellCb); } + + @Test + public void testRegisterBestMatchingNetworkCallback() throws Exception { + final NetworkRequest request = new NetworkRequest.Builder().build(); + assertThrows(UnsupportedOperationException.class, + () -> mCm.registerBestMatchingNetworkCallback(request, new NetworkCallback(), + mCsHandlerThread.getThreadHandler())); + } } diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java index f97eabf6366d..6232423b4f9e 100644 --- a/tests/net/java/com/android/server/IpSecServiceTest.java +++ b/tests/net/java/com/android/server/IpSecServiceTest.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.net.ConnectivityManager; import android.net.INetd; import android.net.IpSecAlgorithm; import android.net.IpSecConfig; @@ -47,6 +48,7 @@ import android.os.Process; import android.system.ErrnoException; import android.system.Os; import android.system.StructStat; +import android.util.Range; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -647,9 +649,9 @@ public class IpSecServiceTest { @Test public void testReserveNetId() { - int start = mIpSecService.TUN_INTF_NETID_START; - for (int i = 0; i < mIpSecService.TUN_INTF_NETID_RANGE; i++) { - assertEquals(start + i, mIpSecService.reserveNetId()); + final Range<Integer> netIdRange = ConnectivityManager.getIpSecNetIdRange(); + for (int netId = netIdRange.getLower(); netId <= netIdRange.getUpper(); netId++) { + assertEquals(netId, mIpSecService.reserveNetId()); } // Check that resource exhaustion triggers an exception @@ -661,7 +663,7 @@ public class IpSecServiceTest { // Now release one and try again int releasedNetId = - mIpSecService.TUN_INTF_NETID_START + mIpSecService.TUN_INTF_NETID_RANGE / 2; + netIdRange.getLower() + (netIdRange.getUpper() - netIdRange.getLower()) / 2; mIpSecService.releaseNetId(releasedNetId); assertEquals(releasedNetId, mIpSecService.reserveNetId()); } diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index a913673c2a1e..1c0ba4f8d8f5 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -357,7 +357,7 @@ public class LingerMonitorTest { NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */, mConnService, mNetd, mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(), - mQosCallbackTracker); + mQosCallbackTracker, new ConnectivityService.Dependencies()); nai.everValidated = true; return nai; } diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java index 5f56e25356c2..9b2a638f8b39 100644 --- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java +++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java @@ -16,11 +16,15 @@ package com.android.server.connectivity; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -34,6 +38,7 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkAgentConfig; +import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.os.Handler; import android.os.test.TestLooper; @@ -72,11 +77,15 @@ public class Nat464XlatTest { Handler mHandler; NetworkAgentConfig mAgentConfig = new NetworkAgentConfig(); - Nat464Xlat makeNat464Xlat() { - return new Nat464Xlat(mNai, mNetd, mDnsResolver) { + Nat464Xlat makeNat464Xlat(boolean isCellular464XlatEnabled) { + return new Nat464Xlat(mNai, mNetd, mDnsResolver, new ConnectivityService.Dependencies()) { @Override protected int getNetId() { return NETID; } + + @Override protected boolean isCellular464XlatEnabled() { + return isCellular464XlatEnabled; + } }; } @@ -99,6 +108,7 @@ public class Nat464XlatTest { mNai.linkProperties.setInterfaceName(BASE_IFACE); mNai.networkInfo = new NetworkInfo(null); mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI); + mNai.networkCapabilities = new NetworkCapabilities(); markNetworkConnected(); when(mNai.connService()).thenReturn(mConnectivity); when(mNai.netAgentConfig()).thenReturn(mAgentConfig); @@ -110,21 +120,23 @@ public class Nat464XlatTest { } private void assertRequiresClat(boolean expected, NetworkAgentInfo nai) { + Nat464Xlat nat = makeNat464Xlat(true); String msg = String.format("requiresClat expected %b for type=%d state=%s skip=%b " + "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(), nai.networkInfo.getDetailedState(), mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(), nai.linkProperties.getLinkAddresses()); - assertEquals(msg, expected, Nat464Xlat.requiresClat(nai)); + assertEquals(msg, expected, nat.requiresClat(nai)); } private void assertShouldStartClat(boolean expected, NetworkAgentInfo nai) { + Nat464Xlat nat = makeNat464Xlat(true); String msg = String.format("shouldStartClat expected %b for type=%d state=%s skip=%b " + "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(), nai.networkInfo.getDetailedState(), mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(), nai.linkProperties.getLinkAddresses()); - assertEquals(msg, expected, Nat464Xlat.shouldStartClat(nai)); + assertEquals(msg, expected, nat.shouldStartClat(nai)); } @Test @@ -194,7 +206,7 @@ public class Nat464XlatTest { } private void checkNormalStartAndStop(boolean dueToDisconnect) throws Exception { - Nat464Xlat nat = makeNat464Xlat(); + Nat464Xlat nat = makeNat464Xlat(true); ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class); mNai.linkProperties.addLinkAddress(V6ADDR); @@ -245,7 +257,7 @@ public class Nat464XlatTest { } private void checkStartStopStart(boolean interfaceRemovedFirst) throws Exception { - Nat464Xlat nat = makeNat464Xlat(); + Nat464Xlat nat = makeNat464Xlat(true); ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class); InOrder inOrder = inOrder(mNetd, mConnectivity); @@ -335,7 +347,7 @@ public class Nat464XlatTest { @Test public void testClatdCrashWhileRunning() throws Exception { - Nat464Xlat nat = makeNat464Xlat(); + Nat464Xlat nat = makeNat464Xlat(true); ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class); nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX)); @@ -372,7 +384,7 @@ public class Nat464XlatTest { } private void checkStopBeforeClatdStarts(boolean dueToDisconnect) throws Exception { - Nat464Xlat nat = makeNat464Xlat(); + Nat464Xlat nat = makeNat464Xlat(true); mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64")); @@ -414,7 +426,7 @@ public class Nat464XlatTest { } private void checkStopAndClatdNeverStarts(boolean dueToDisconnect) throws Exception { - Nat464Xlat nat = makeNat464Xlat(); + Nat464Xlat nat = makeNat464Xlat(true); mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64")); @@ -450,7 +462,7 @@ public class Nat464XlatTest { final IpPrefix prefixFromDns = new IpPrefix(NAT64_PREFIX); final IpPrefix prefixFromRa = new IpPrefix(OTHER_NAT64_PREFIX); - Nat464Xlat nat = makeNat464Xlat(); + Nat464Xlat nat = makeNat464Xlat(true); final LinkProperties emptyLp = new LinkProperties(); LinkProperties fixedupLp; @@ -486,10 +498,57 @@ public class Nat464XlatTest { assertEquals(null, fixedupLp.getNat64Prefix()); } + private void checkClatDisabledOnCellular(boolean onCellular) throws Exception { + // Disable 464xlat on cellular networks. + Nat464Xlat nat = makeNat464Xlat(false); + mNai.linkProperties.addLinkAddress(V6ADDR); + mNai.networkCapabilities.setTransportType(TRANSPORT_CELLULAR, onCellular); + nat.update(); + + final IpPrefix nat64Prefix = new IpPrefix(NAT64_PREFIX); + if (onCellular) { + // Prefix discovery is never started. + verify(mDnsResolver, never()).startPrefix64Discovery(eq(NETID)); + assertIdle(nat); + + // If a NAT64 prefix comes in from an RA, clat is not started either. + mNai.linkProperties.setNat64Prefix(nat64Prefix); + nat.setNat64PrefixFromRa(nat64Prefix); + nat.update(); + verify(mNetd, never()).clatdStart(anyString(), anyString()); + assertIdle(nat); + } else { + // Prefix discovery is started. + verify(mDnsResolver).startPrefix64Discovery(eq(NETID)); + assertIdle(nat); + + // If a NAT64 prefix comes in from an RA, clat is started. + mNai.linkProperties.setNat64Prefix(nat64Prefix); + nat.setNat64PrefixFromRa(nat64Prefix); + nat.update(); + verify(mNetd).clatdStart(BASE_IFACE, NAT64_PREFIX); + assertStarting(nat); + } + } + + @Test + public void testClatDisabledOnCellular() throws Exception { + checkClatDisabledOnCellular(true); + } + + @Test + public void testClatDisabledOnNonCellular() throws Exception { + checkClatDisabledOnCellular(false); + } + static void assertIdle(Nat464Xlat nat) { assertTrue("Nat464Xlat was not IDLE", !nat.isStarted()); } + static void assertStarting(Nat464Xlat nat) { + assertTrue("Nat464Xlat was not STARTING", nat.isStarting()); + } + static void assertRunning(Nat464Xlat nat) { assertTrue("Nat464Xlat was not RUNNING", nat.isRunning()); } diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index e4e24b464838..fec5ef39374a 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -48,18 +48,22 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; import android.net.INetd; import android.net.UidRange; +import android.net.Uri; import android.os.Build; import android.os.SystemConfigManager; import android.os.UserHandle; @@ -70,12 +74,11 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.server.LocalServices; -import com.android.server.pm.PackageList; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.AdditionalAnswers; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; @@ -112,7 +115,6 @@ public class PermissionMonitorTest { @Mock private Context mContext; @Mock private PackageManager mPackageManager; @Mock private INetd mNetdService; - @Mock private PackageManagerInternal mMockPmi; @Mock private UserManager mUserManager; @Mock private PermissionMonitor.Dependencies mDeps; @Mock private SystemConfigManager mSystemConfigManager; @@ -131,16 +133,14 @@ public class PermissionMonitorTest { when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE)) .thenReturn(mSystemConfigManager); when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]); + final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext)); + doReturn(UserHandle.ALL).when(asUserCtx).getUser(); + when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx); mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps)); - LocalServices.removeServiceForTest(PackageManagerInternal.class); - LocalServices.addService(PackageManagerInternal.class, mMockPmi); - when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(new ArrayList<String>(), - /* observer */ null)); when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null); mPermissionMonitor.startMonitoring(); - verify(mMockPmi).getPackageList(mPermissionMonitor); } private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid, @@ -770,4 +770,32 @@ public class PermissionMonitorTest { INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{ MOCK_UID2 }); } + + @Test + public void testIntentReceiver() throws Exception { + final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); + final ArgumentCaptor<BroadcastReceiver> receiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + verify(mContext, times(1)).registerReceiver(receiverCaptor.capture(), any(), any(), any()); + final BroadcastReceiver receiver = receiverCaptor.getValue(); + + // Verify receiving PACKAGE_ADDED intent. + final Intent addedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED, + Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */)); + addedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1); + setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1, + new String[] { INTERNET, UPDATE_DEVICE_STATS }); + receiver.onReceive(mContext, addedIntent); + mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET + | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[] { MOCK_UID1 }); + + // Verify receiving PACKAGE_REMOVED intent. + when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(null); + final Intent removedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED, + Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */)); + removedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1); + receiver.onReceive(mContext, removedIntent); + mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[] { MOCK_UID1 }); + } + } diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 1d459a347526..1ef1a61f17ea 100644 --- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -194,29 +194,35 @@ public class UnderlyingNetworkTrackerTest { } private NetworkRequest getWifiRequest() { - return getExpectedRequestBase() + return getExpectedRequestBase(true) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); } private NetworkRequest getCellRequestForSubId(int subId) { - return getExpectedRequestBase() + return getExpectedRequestBase(false) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) .build(); } private NetworkRequest getRouteSelectionRequest() { - return getExpectedRequestBase().build(); + return getExpectedRequestBase(true).build(); } - private NetworkRequest.Builder getExpectedRequestBase() { - return new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + private NetworkRequest.Builder getExpectedRequestBase(boolean requireVcnManaged) { + final NetworkRequest.Builder builder = + new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + + if (requireVcnManaged) { + builder.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } + + return builder; } @Test diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 4bf849111a5d..0e5f5e43f282 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -73,7 +73,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1); - mIkeSession = mGatewayConnection.buildIkeSession(); + mIkeSession = mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network); mGatewayConnection.setIkeSession(mIkeSession); mGatewayConnection.transitionTo(mGatewayConnection.mConnectedState); diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index d07d2cf4f1bb..7afa4494ee8b 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -25,12 +25,15 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.net.ipsec.ike.IkeSessionParams; + import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; /** Tests for VcnGatewayConnection.ConnectingState */ @RunWith(AndroidJUnit4.class) @@ -51,7 +54,12 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio @Test public void testEnterStateCreatesNewIkeSession() throws Exception { - verify(mDeps).newIkeSession(any(), any(), any(), any(), any()); + final ArgumentCaptor<IkeSessionParams> paramsCaptor = + ArgumentCaptor.forClass(IkeSessionParams.class); + verify(mDeps).newIkeSession(any(), paramsCaptor.capture(), any(), any(), any()); + assertEquals( + TEST_UNDERLYING_NETWORK_RECORD_1.network, + paramsCaptor.getValue().getConfiguredNetwork()); } @Test diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index 661e03af4f84..99feffdebc8e 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -38,7 +38,8 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec public void setUp() throws Exception { super.setUp(); - mGatewayConnection.setIkeSession(mGatewayConnection.buildIkeSession()); + mGatewayConnection.setIkeSession( + mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_2.network)); // ensure that mGatewayConnection has an underlying Network before entering // DisconnectingState diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 748c7924685d..d08af9dd3370 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -18,6 +18,7 @@ package com.android.server.vcn; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; @@ -87,6 +88,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private void verifyBuildNetworkCapabilitiesCommon(int transportType) { final NetworkCapabilities underlyingCaps = new NetworkCapabilities(); underlyingCaps.addTransportType(transportType); + underlyingCaps.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); underlyingCaps.addCapability(NET_CAPABILITY_NOT_METERED); underlyingCaps.addCapability(NET_CAPABILITY_NOT_ROAMING); |